(Basic Python tutorial) learning notes | Chapter 2 | magic methods, attributes, and iterators
This chapter is a little abstract and looks a little painful!
Double underline _ ure _ or single underline has special meanings. in Python, the set of these names is called the magic method: the most important is _ init _ and some methods for processing access objects. These methods allow you to create your own sequences or mappings.
------
Preparations:
Put _ metaclass __= type at the beginning of the module to ensure the latest class. Consider the following two classes
class NewStyle(object): more_code_hereclass OldStyle: more_code_here
If the file starts with _ metclass __= type, this class is a new class.
------
Constructor:
Unlike normal methods, constructor is called immediately after an object is created. Therefore
>>>f = FooBar()>>>f.init()
Equivalent
>>>f = FooBar()>>> class FooBar:def __init__(self):self.var = 42>>> f = FooBar()>>> f.var42
# What if there are default parameters?
>>> Class Foobar: def _ init _ (self, value = 42): self. var = value >>> f = Foobar () # If no parameter exists, use the default value >>> f. var42 >>> f1 = Foobar (44) # if there is a parameter, use the new parameter >>> f1.var44
In Python, _ init _ is the most commonly used one.
In Python, there is a magic method _ del __, destructor method, which is called before the object is to be reclaimed by garbage collection. However, the specific time of the call is unknown.
Therefore, we try our best to avoid using the _ del _ function.
------
Override the general method and special constructor:
>>> class A:... def hello(self):... print 'Hello,World!'...>>> class B(A): pass...>>> class C(B): pass...
# Look at their working mechanism
# C is an example of C class. When c calls hello (), First find whether your class exists. If no, find it in super class B. If no,
Find the superclass. If not, an error is returned.
>>> c = C()>>> c.hello()Hello,World!
If I rewrite Class B, what about the hello method?
>>> 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!
Rewriting is an important part of the inheritance mechanism and is especially important for Constructor methods. The constructor is used to initialize the state of the newly created object. Most subclasses not only have their own initialization code, but also have super class initialization code. Although the rewrite mechanism is the same for all methods, when dealing with constructor methods, it is more likely to encounter a special problem: If the constructor of a class is overwritten, you need to call the superclass constructor. Otherwise, the object will not be correctly initialized. See the following example.
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print Ahaha... self.hungry = False else: print No, Thanks!
This class defines the basic skills that birds can eat. If they are full, they will not eat any more.
Output result:
>>> B = Bird () >>> B. eat () Ahaha... >>> B. eat () No, Thanks! The following subclass SingBird, class SingBird (Bird): def _ init _ (self): self. sound = 'squawk' def sing (self): print self. sound
Output result:
>>> s = SingBird()>>> s.sing()squawk
SingBird is a child of Bird, but if you call the eat () method of the Bird class,
>>> s.eat()Traceback (most recent call last): File
, line 1, in
s.eat() File D:LearnPythonPerson.py, line 42, in eat if self.hungry:AttributeError: SingBird instance has no attribute 'hungry'
The code error is clear. The initialization code in SingBird is overwritten, but there is no code to initialize hungry.
------
Call the unbound superclass constructor:
Class SingBird (Bird): def _ init _ (self): Bird. _ init _ (self) # Add this line of code to handle self. sound = 'squawk' def sing (self): print self. sound >>> sb = SingBird () >>> sb. sing () squawk> sb. eat () Ahaha...> sb. eat () No, Thanks!
------
Use the super function:
__metaclass__=typeclass Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print Ahaha... self.hungry = False else: print No, Thanks!class SingBird(Bird): def __init__(self): super(SingBird,self).__init__() self.sound = 'squawk' def sing(self): print self.sound
Note:
1. _ metaclass __= type is required. Otherwise, the following error is returned:
>>> sb = SingBird()Traceback (most recent call last): File
, line 1, in
sb = SingBird() File D:LearnPythonPerson.py, line 51, in __init__ super(SingBird,self).__init__()TypeError: must be type, not classobj
2. super (SingBird, self). _ init _ () has such a sentence
Output result:
>>> sb = SingBird()>>> sb.sing()squawk>>> sb.eat()Ahaha...>>> sb.eat()No, Thanks!
------
Basic sequence and ing rules:
Sequence and ing are the collection of objects. To achieve their basic behavior, if the object is unchangeable, two magic methods are required. If the object is changeable, four magic methods are required.
_ Len _ (self): returns the number of items contained in the set.
_ Getitem _ (self, key): returns the value corresponding to the given key.
_ Setitem _ (self, key, value): stores key-related values in a certain method.
_ Delitem _ (self, key): deletes the key related to the object.
In practice, create an infinite sequence
def checkIndex(key): if not isinstance(key,(int,long)): raise TypeError if key<0: raise IndexErrorclass ArithmeticSequence: def __init__(self,start=0,step=1): self.start = start self.step = step self.changed = {} def __getitem__(self,key): checkIndex(key) try: return self.changed[key] except KeyError: return self.start + key*self.step def __setitem__(self,key,value): checkIndex(key) self.changed[key] = value
Output result
>>> s[100]201>>> s = ArithmeticSequence(1,2)>>> s[4]9>>> s[10]21>>> del s[4]Traceback (most recent call last): File
, line 1, in
del s[4]AttributeError: ArithmeticSequence instance has no attribute '__delitem__'>>> s['four']Traceback (most recent call last): File
, line 1, in
s['four'] File D:LearnPythonPerson.py, line 71, in __getitem__ checkIndex(key) File D:LearnPythonPerson.py, line 62, in checkIndex raise TypeErrorTypeError>>> s[-4]Traceback (most recent call last): File
, line 1, in
s[-4] File D:LearnPythonPerson.py, line 71, in __getitem__ checkIndex(key) File D:LearnPythonPerson.py, line 64, in checkIndex raise IndexErrorIndexError
------
Subclass list, dictionary, and string
Three sequence and ing rules (UserList, UserString, UserDict). If you want to implement a sequence that is similar to the built-in list behavior, you can use the subclass list to see the following example, list with access count
class CounterList(list): def __init__(self,*args): super(CounterList,self).__init__(*args) self.counter = 0 def __getitem__(self,index): self.counter +=1 return super(CounterList,self).__getitem__(index)
# Below are some examples of how she uses
>>> c = CounterList(range(10))>>> c[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> c.reverse()>>> c[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]>>> del c[3:6]>>> c[9, 8, 7, 3, 2, 1, 0]>>> c.counter0>>> c[4]+c[2]9>>> c.counter2
# Others have the same performance as list, but there is a counter feature that will automatically increase after each addition.
------
Attribute:
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.width150
------
PropertyFunction:
__metaclass__=typeclass 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 size = property(getSize,setSize)
In this new version of Rectangle, the property function creates an attribute, in which the accessors function is used as a parameter (values first and then values), and the attribute is named size. In this way, you don't have to worry about how it is implemented. You can process width, height, and size in the same way.
>>> r = Rectangle()>>> r.width = 10>>> r.height= 20>>> r.size(10, 20)>>> r.size = 100,200>>> r.width100
The property function can be called using 0, 1, 2, 3, or 4 parameters. If no parameter exists, the generated attribute cannot be read or written. If only one parameter is used for calling, the generated attribute is read-only 3rd parameters. Name: fget, fset, fdel, doc __
------
Static methods and class member Methods
Static methods and class member methods are loaded into Staticmethod and Classmethod objects at creation.
The definition of a static method does not include the self parameter and may be directly called by the class itself.
When defining a class method, a parameter similar to self named cls is required. The class member method can be called directly using a specific object of the class. However, the cls parameter is automatically bound to a class. Let's take a look at the example:
class MyClass: def smeth(): print 'This is a stacie method' smeth = staticmethod(smeth) def cmeth(cls): print 'This is a class method of', cls cmeth = classmethod(cmeth)
# Replace @
__metaclass__ = typeclass MyClass: @staticmethod def smeth(): print 'This is a stacie method' @classmethod def cmeth(cls): print 'This is a class method of', cls
# After defining the method, you can call it like this.
>>> MyClass.smeth()This is a stacie method>>> MyClass.cmeth()This is a class method of
------
_ Getattr __,__ setattr __
Some magic methods must be used to execute code when accessing features. The following four methods provide the required functions.
_ Getattrbute _ (self, name): When the feature name is accessed, it is automatically called.
_ Getattr _ (self, name): it is automatically called when the feature name is accessed and the object does not have the corresponding feature.
_ Setattr _ (self, name, value): this parameter is automatically called when you try to assign a value to the feature name.
_ Delattr _ (self, name): it is automatically called when you try to delete the feature name.
class Rectangle: def __init__(self): self.width = 0 self.height = 0 def __setattr__(self,name,value): if name == 'size': self.width,self.height = value else: self.__dict__[name] = value def __getattr__(self,name): if name == 'size': return self.width,self.height else: raise AttributeError
------
Iterator:
The special method __iter _ is the basis of the iterator rule. The _ iter _ method returns an iterator. The so-called iterator is the object with the next method. If next is called but no value can be returned, the StopIteration exception will be returned. Why should I use the iterator instead of the list?
If there are many values, the list will be obtained at one time, which will occupy too much memory. Iteration can be obtained one by one. The reason for using the iterator is as follows:
The iterator is more common, simpler, and more elegant.
class Fibs: def __init__(self): self.a = 0 self.b = 1 def next(self): self.a,self.b = self.b,self.a + self.b return self.a def __iter__(self): return self
First, the _ iter _ method is implemented. This method actually returns the iterator itself. In many cases, __iter _ is placed in the object used in the for loop. First, a Fibs object is generated.
>>> Fig ()
Next, you can use this object in the for loop-for example, to find the smallest number in a number greater than 1000 in the Fibonacci sequence:
>>> for f in fibs:if f>1000:print fbreak1597
Note: The built-in function iter can obtain the iterator from the iteratable objects.
>>> it = iter([1,2,3])>>> it.next()1>>> it.next()2
In addition, it can also obtain iterated objects from functions or other callable objects.
------
Obtain the sequence from the iterator:
In addition to the iterations and iteratable objects, they can also be converted into sequences. In most cases, sequences can be replaced with iterators. A useful example is to use the list constructor to explicitly convert an iterator to a list.
class TestIter: value = 0 def next(self): self.value +=1 if self.value > 10 : raise StopIteration return self.value def __iter__(self):
Output result:
>>> ti = TestIter()>>> ti<__main__.TestIter instance at 0x0000000002A81A08>>>> list(ti)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
------
Generator: A new concept introduced by Python. It is also called a simple Generator for historical reasons. It and the iterator may be two of the most powerful features introduced in recent years. The generator can help programmers write very elegant code. Of course, writing any program is not usable. A generator is an iterator defined by common function syntax.
------
Create a generator:
Nested = [[1, 2], [3, 4], [5]. How can I print the numbers one by one in an example like this.
def flatten(nested): for sublist in nested: for element in sublist: yield element
# How to include yield statements, called generators
>>> nested = [[1],[2,3],[4,5,6]]>>> flatten(nested)
>>> for num in flatten(nested): print num 123456
------
Recursive generator:
The generator created in the previous example can only process two layers of nesting and uses two for loops. What if I want to process any layer nesting? It should be more flexible, and now it's time for the recursive generator to appear.
def flatten(nested): try: for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested
There are two situations: basic and recursive.
1. If it is only an element, the function is told to expand an element. In this case, the for Loop will cause a TypeError exception and the generator will generate an element.
2. For a list, special processing is required. The program must traverse all child lists and call flatten for them. Then, it uses another for loop to generate all the elements in the expanded child list. That's amazing.
>>> Nested = [[[1, 2], 3], 4], 5]
>>> List (flatten (nested ))
[1, 2, 3, 4, 5]
If it is a string object, it is a sequence and does not cause TypeError. If you do not want to iterate on such objects. To handle this situation, you must add a check statement at the beginning of the generator. Try to splice the input object with a string to see if there is a TypeError. This is the easiest and quickest way to check whether an object is similar to a string. Add the generator of the check statement below.
>>> Nested = ['A', [[1, 2], 3], 4], 5]
>>> List (flatten (nested ))
['A', 1, 2, 3, 4, 5]
------
General generator:
A generator is a function that contains the yield keyword. When called, the code in the function body is not executed, but an iterator is returned. Each time a value is requested, the code in the generator is executed, knowing that a yield or return statement is encountered. Yield means that a value should be generated. The return statement indicates that the generator must stop executing the statement. In other words, a generator consists of two parts: the generator function and the generator iterator. Generator functions are defined using def statements, including the yield part. The generator iterator is the part returned by this function.
>>> def simple_generator():yield 1>>> simple_generator
>>> simple_generator()
>>>
------
Generator method:
>>> def repeater(value): while True: new = (yield value) if new is not None: value = new
Output result:
>>> r = repeater(42)>>> r.next()42>>> r.next()42>>> r.send('Hello,World!')'Hello,World!'
# Next () method, send () method, throw () method, close () method
------
Simulation generator:
How to use a common function simulation Generator
First, place the following statement at the beginning of the program.
Result = []
Then, run the following code:
Yield some_expression
Replace the following statement:
Result. append (some_expression)
Add the following statement at the end of the function:
Return result
The following is the version of the flatten generator that is rewritten using a common function.
def flatten(nested): result = [] try: try: nested + '' except TypeError: pass else: raise TypeError for sublist in nested: for element in flatten(sublist): result.append(element) except TypeError: result.append(nested) return result
Output result:
>>> n = [[[[[['HaHa...'],1],2],3],4],5]>>> flatten(n)['HaHa...', 1, 2, 3, 4, 5]
------
Iter (obj) obtains the iterator from an iteratable object.
Property (fget, fset, fdel, doc) returns an attribute. All parameters are optional.
Super (class, obj) returns the bound instance of a class's superclass