预计阅读本页时间:-
A Third Example
On to another example. This time, we’ll define a subclass of SecondClass that implements three specially named attributes that Python will call automatically:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
- __init__ is run when a new instance object is created (self is the new ThirdClass object).[60]
- __add__ is run when a ThirdClass instance appears in a + expression.
- __str__ is run when an object is printed (technically, when it’s converted to its print string by the str built-in function or its Python internals equivalent).
Our new subclass also defines a normally named method named mul, which changes the instance object in-place. Here’s the new subclass:
>>> class ThirdClass(SecondClass): # Inherit from SecondClass
... def __init__(self, value): # On "ThirdClass(value)"
... self.data = value
... def __add__(self, other): # On "self + other"
... return ThirdClass(self.data + other)
... def __str__(self): # On "print(self)", "str()"
... return '[ThirdClass: %s]' % self.data
... def mul(self, other): # In-place change: named
... self.data *= other
...
>>> a = ThirdClass('abc') # __init__ called
>>> a.display() # Inherited method called
Current value = "abc"
>>> print(a) # __str__: returns display string
[ThirdClass: abc]
>>> b = a + 'xyz' # __add__: makes a new instance
>>> b.display() # b has all ThirdClass methods
Current value = "abcxyz"
>>> print(b) # __str__: returns display string
[ThirdClass: abcxyz]
>>> a.mul(3) # mul: changes instance in-place
>>> print(a)
[ThirdClass: abcabcabc]
ThirdClass “is a” SecondClass, so its instances inherit the customized display method from SecondClass. This time, though, ThirdClass creation calls pass an argument (e.g., “abc”). This argument is passed to the value argument in the __init__ constructor and assigned to self.data there. The net effect is that ThirdClass arranges to set the data attribute automatically at construction time, instead of requiring setdata calls after the fact.
Further, ThirdClass objects can now show up in + expressions and print calls. For +, Python passes the instance object on the left to the self argument in __add__ and the value on the right to other, as illustrated in Figure 26-3; whatever __add__ returns becomes the result of the + expression. For print, Python passes the object being printed to self in __str__; whatever string this method returns is taken to be the print string for the object. With __str__ we can use a normal print to display objects of this class, instead of calling the special display method.
Figure 26-3. In operator overloading, expression operators and other built-in operations performed on class instances are mapped back to specially named methods in the class. These special methods are optional and may be inherited as usual. Here, a + expression triggers the __add__ method.
Specially named methods such as __init__, __add__, and __str__ are inherited by subclasses and instances, just like any other names assigned in a class. If they’re not coded in a class, Python looks for such names in all its superclasses, as usual. Operator overloading method names are also not built-in or reserved words; they are just attributes that Python looks for when objects appear in various contexts. Python usually calls them automatically, but they may occasionally be called by your code as well; the __init__ method, for example, is often called manually to trigger superclass constructors (more on this later).
Notice that the __add__ method makes and returns a new instance object of its class, by calling ThirdClass with the result value. By contrast, mul changes the current instance object in-place, by reassigning the self attribute. We could overload the * expression to do the latter, but this would be too different from the behavior of * for built-in types such as numbers and strings, for which it always makes new objects. Common practice dictates that overloaded operators should work the same way that built-in operator implementations do. Because operator overloading is really just an expression-to-method dispatch mechanism, though, you can interpret operators any way you like in your own class objects.