Home >Backend Development >Python Tutorial >Detailed explanation of python magic method
Preparation
To ensure that the class is a new type, you should put _metaclass_=type at the beginning of your module.
class NewType(Object): mor_code_here class OldType: mor_code_here
Among these two classes, NewType is the new class and OldType belongs to the old class. If _metaclass_=type is added in front, then both classes belong to the new class.
Constructor
Constructor is different from its method. When an object is created, the constructor will be called immediately. Creating a Python constructor is very simple. Just convert the init method from the simple init method to the magic version of the _init_ method.
class FooBar: def __init__(self): self.somevar = 42 >>> f =FooBar() >>> f.somevar 42
Override a general method
Every class may have one or more superclasses (parent classes), and they inherit behavior methods from the superclasses.
class A: def hello(self): print 'hello . I am A.' class B(A): pass >>> a = A() >>> b = B() >>> a.hello() hello . I am A.
Because class B does not have a hello method and class B inherits class A, the hello method of class A will be called.
The most basic way to add functionality to a subclass is to add methods. But you can also override some superclass methods to customize inherited behavior. As follows:
class A: def hello(self): print 'hello . I am A.' class B(A): def hello(self): print 'hello . I am B' >>> b = B() >>> b.hello() hello . I am B
Special and constructor methods
Overriding is an important part of the inheritance mechanism, especially for constructors. Look at the following example:
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print 'Aaaah...' self.hungry = False else: print 'No, thanks!' >>> b = Bird() >>> b.eat() Aaaah... >>> b.eat() No, thanks!
This class defines the bird’s ability to eat. After it eats once, it will no longer be hungry again. You can clearly see it through the above execution results.
Then use the SongBird class to inherit the Bird class and add the singing method to it:
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print 'Aaaah...' self.hungry = False else: print 'No, thanks!' class SongBird(Bird): def __init__(self): self.sound = 'Squawk!' def sing(self): print self.sound >>> s = SongBird() >>> s.sing() Squawk! >>> s.eat() Traceback (most recent call last): File "<pyshell#26>", line 1, in <module> s.eat() File "C:/Python27/bird", line 6, in eat if self.hungry: AttributeError: 'SongBird' object has no attribute 'hungry'
The exception clearly illustrates the error: SongBird does not have the hungry feature. The reason is this: in SongBird, the constructor is rewritten, but the new constructor does not have any code about initializing the hungry properties. In order to achieve the desired effect, the constructor of SongBird must call the constructor of its superclass Bird to ensure basic initialization.
Two methods to implement:
1. Call the unbound superclass constructor
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print 'Aaaah...' self.hungry = False else: print 'No, thanks!' class SongBird(Bird): def __init__(self): Bird.__init__(self) self.sound = 'Squawk!' def sing(self): print self.sound >>> s = SongBird() >>> s.sing() Squawk! >>> s.eat() Aaaah... >>> s.eat() No, thanks!
Add a line of code Bird.__init__(self) to the SongBird class. When a method on an instance is called, the method's self parameter is automatically bound to the instance (this is called a bound method). But if you call the class method directly, then no instance will be bound. This allows you to freely provide the required self parameters (such methods are called unbound methods).
By providing the current instance as the self parameter to the unbound method, SongBird can use all implementations of its superclass constructor, which means that the hungry attribute can be set.
2. Use the super function
__metaclass__ = type #表明为新式类 class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print 'Aaaah...' self.hungry = False else: print 'No, thanks!' class SongBird(Bird): def __init__(self): super(SongBird,self).__init__() self.sound = 'Squawk!' def sing(self): print self.sound >>> s.sing() Squawk! >>> s.eat() Aaaah... >>> s.eat() No, thanks!
The super function can only be used in new-style classes. The current class and object can be used as parameters of the super function. Any method that calls the object returned by the function calls the method of the super class, not the current class. Then you can use super(SongBird, self) directly instead of using Bird in the constructor of SongBird.
Property
The accessor is a simple method that can use names like getHeight and setHeight to get or rebind some properties. Encapsulating state variables like this is important if some action must be taken when a given feature is accessed. As follows:
class Rectangle: def __init__(self): self.width = 0 self.height = 0 def setSize(self,size): self.width , self.height = size def getSize(self): return self.width , self.height >>> r = Rectangle() >>> r.width = 10 >>> r.height = 5 >>> r.getSize() (10, 5) >>> r.setSize((150,100)) >>> r.width 150
In the above example, the getSize and setSize methods are accessor methods of an imaginary property called size, where size is a tuple consisting of width and height.
property function
property function is very simple to use. If you have already written a class like Rectangle in the previous section, then just add a line of code:
__metaclass__ = type class Rectangle: def __int__(self): self.width = 0 self.height = 0 def setSize(self,size): self.width, self.height = size def getSize(self): return self.width ,self.height size = property(getSize ,setSize) >>> r = Rectangle() >>> r.width = 10 >>> r.height = 5 >>> r.size (10, 5) >>> r.size = 150,100 >>> r.width 150
In this new version of Retangle , the property function creates a property in which the accessor function is used as a parameter (first gets the value, then assigns the value), and the property is named size. This way you no longer need to worry about how it is implemented, you can handle width, height and size in the same way.