Hope to continue to update through the blog park, share and record the basic knowledge of Python to the advanced application of the dots drop!
Nineth Wave: Chapter 9th Magic Methods, attributes, and iterators
in Python, some names are preceded and followed by a two underline, which is a very special notation. There have been some such names (such as __future__), which means that the name has a special meaning, and that it should never be used in its own program.
In Python, a collection of these names consists of methods called magic methods (or special methods). If an object implements one of these methods, the method is called by Python under special circumstances, and there is little need to invoke them directly.
Discuss some important magic methods (the most important are the __init__ method and some methods for dealing with object access, which allow you to create your own sequences or mappings). It also handles two related topics: attributes (which are handled by magic methods in previous versions of Python, now through property functions) and iterators (using the Magic method __iter__ to allow iterators to be used in a for loop).
[9.1] Preparatory work
There is no "legacy" class in Python3.0, and you do not need to explicitly subclass object or set the Meta class to type (__metaclass__=type). All classes are implicitly called subclasses of object---if there is no explicit superclass, it is directly subclasses, otherwise it is indirectly subclasses.
[9.2] Construction method
The first magic method to be discussed first is to construct a method. The construction method is a very peculiar name, which represents a similar initialization method called Init. But the construction method differs from other common methods in that when an object is created, the constructor is called immediately.
For example:
>>> F=foobar ()
>>> F.init ()
The construction method simplifies it to the following form:
>>> F=foobar ()
Creating a construction method in Python is easy. Just change the name of the Init method from simple init to magic version __init__:
Class FooBar ():
def __init__ (self):
Self.somevar=42
Of all the magic methods in Python, __init__hi uses the most. There is a magic method called __del__, which is the destructor method. It is called before the object is garbage collected, but the exact time at which the call occurs is unknowable. Therefore, it is recommended that readers try to avoid using the __del__ function.
[9.2.1] overriding general methods and special construction methods
Each class may have one or more superclass, which inherit the behavior from the superclass. If a method is called (or a property is accessed) in an instance of Class B, but the method is not found in class B, it is searched for in his superclass a.
Class A:
def hello (self):
Print "Hello,i ' m a!"
Class B (A):
Pass
Class A defines a method called Hello, which is inherited by Class B. Because Class B does not have its own Hello method defined, when Hello is called, it goes to the super Class A to find the Hello method.
The most basic way to add functionality to subclasses is to add methods. However, you can also override some superclass methods to customize the behavior of the inheritance. Class B can also override this method. For example, the definition of Class B in the following example has been modified.
Class B (A):
def hello (self):
Print "Hello,i ' m B"
Rewriting is an important part of the inheritance mechanism, which is especially important for construction methods. The constructor method is used to initialize the state of the newly created object, and most subclasses not only have their own initialization code, but also the initialization code of the superclass. Although the overriding mechanism is the same for all methods, it is more likely to encounter special problems when dealing with construction methods than overriding common methods: if the constructor of a class is overridden, then the constructor of the superclass needs to be called, otherwise the object may not be initialized correctly.
Consider the following Bird class:
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
Because Songbird is a subclass of bird, it integrates the Eat method, but if the Eat method is called, a problem arises:
>>>sb.eat ()
Attributeerror:songbird instance has no attribute ' hungry '
The exception clearly illustrates the error: Songbird has no hungry feature. The reason is this: in Songbird, the constructor method is overridden, but the new constructor does not have any code for initializing the hungry attribute. To achieve the desired effect, the Songbird constructor must call its superclass bird construction method to ensure basic initialization. There are two ways to do this: call the unbound version of the superclass construction method, or use the Super function.
[9.2.2] Call Unbound superclass construction method
In fact, it is very easy and useful to call the construction method of tea class. Here's a workaround for the problem raised at the end of the previous section.
Class SongBird (Bird):
def __init__ (self):
Bird.__init__ (self)
Self.sound= ' squawk! '
def sing (self):
Print Self.sound
Only one line of code bird.__init__ (self) has been added to the Songbird class. Why is there such a result? When you invoke the method of an instance, the self parameter of the method is automatically bound to the instance (this is called the binding method). However, if the method of the class is called directly (such as bird.__init__), then no instance will be bound for long. This gives you the freedom to provide the self parameter you need. Such a method is called an unbound method.
By providing the current instance as the self parameter to the unbound method, Songbird is able to use all the implementations of its superclass construction method, which means that the property hungry can be set.
[9.2.3] using the Super function
The current class and object can be used as arguments to the Super function, and any method that invokes the object returned by the function is called a method of the superclass, not the method of the current class. Instead of using bird in the SongBird construction method, you can use Super (songbird,self) directly.
__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
[9.3] member access
This section discusses a useful collection of magical methods that can create objects that behave like sequences or mappings.
The rules for basic sequences and mappings are simple, but if you want to implement them all, you need to implement a lot of magic functions.
[9.3.1] Basic sequence and mapping rules
Sequences and mappings are collections of objects. In order to achieve their basic behavior, if the object is immutable, it takes two magical methods to use it for a long time, and 4 if it is mutable.
__len__ (self): This method should return the number of items contained in the collection. For a sequence, it is the number of elements, and in the case of a map, the amount of key-value pairs. If __len__ returns 0, the object is treated as a false value (empty list, tuple, string, and Dictionary) in a Boolean variable.
__getitem__ (Self,key): This method returns the value corresponding to the given key. For a sequence, the key should be a 0~n-1 integer, n is the length of the sequence, and for the mapping, any kind of key can be used.
__setitem__ (Self,key,value): This method should store key-related value in a certain way. This value can then be obtained using __getitem__ (Self,key). Of course, this method can only be defined for an object that is modifiable.
__delitem__ (Self,key): This method is called when a del statement is used on a subset of objects, and the key associated with the element must be deleted. This method is also defined for modifiable objects.
Additional requirements for these methods:
For a sequence, if the key is a negative integer, the count starts at the end. In other words, x[-n] and [Len (x)-n] are the same;
If the key is an inappropriate type, a TypeError exception is thrown;
If the index of the sequence is the correct type, but is out of range, a Indexerror exception should be thrown.
The following example creates an infinite sequence:
def checkindex (key):
"""
is the key given to be an acceptable index?
In order to be accepted, the key should be a nonnegative integer, and if it is not an integer, it will throw a typeerror; if it is a negative number, it will throw a indexerror
"""
If not isinstance (key, (Int,long)): Raise TypeError
If Key<0:raise indexerror
Class Arithmeticsequence:
def __init__ (self,start=0,setp=1):
"""
Initializing an arithmetic sequence
Initial value---the first value in a sequence
Step---The difference between two adjacent values
Changing the Dictionary of values---user modified
"""
Self.strt=start
Self.step=step
self.changed={}
def __getitem__ (Self,key):
"""
Get an item from the arithmetic sequence.
"""
CheckIndex (Key)
Try:return Self.changed[key]
Except Keyerror:
Return SELF.START+KEY*SELF.STRP
def __setitem__ (Self,key,value):
"""
To modify an item in an arithmetic sequence
"""
CheckIndex (Key)
Self.changed[key]=value
[9.3.2] Subclass lists, dictionaries and strings
The 4 methods of the basic sequence, mapping rules have been introduced so far. The key word is inheritance, can inherit the time why should all realize? The standard library has 3 implementations about sequence and mapping rules (UserList, userstring, userdict) that can be used immediately. You can subclass built-in types (note that if the behavior of a class is close to the default behavior it is useful to re-write a class if you need to re-implement most of the methods).
Therefore, if you want to implement a sequence that is similar to the built-in list behavior, you can use the subclass list. When a subclass of a built-in type---such as list, it also indirectly to the object subclass. Automatically becomes a new class, which means you can use features like the Super function.
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)
The Counterlist class relies heavily on the behavior of its subclass superclass list. The Counterlist class does not rewrite any method and can be used directly. Of the two overridden methods, the Super method is used to invoke the corresponding superclass method. The behavior of the desired initialization counter attribute is added only in __init__, and the counter attribute is updated in __getitem__.
[9.4] More Magic
There are many uses for magic names. Most of the special methods are prepared for advanced usage.
[9.5] Properties
An accessor method has been mentioned. Accessors are an easy way to use names such as GetHeight, setheight to get or rebind some attributes (possibly private properties of a class). If you have to take some action when accessing a given attribute, it is important to encapsulate state variables (attributes) like this.
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
In the example above, the GetSize and SetSize methods are accessor methods for an imaginary attribute named size. Size is a tuple consisting of width and height. Python can hide accessor methods, making all features look the same. These attributes, defined by accessors, are called properties.
There are two mechanisms for creating attributes in Python. This paper discusses the new mechanism for using the property functions in the modern class, and then simply explains how to implement the properties using special methods.
[9.5.1] Property function
The use of the property function is simple, like the rectangle class in the previous section, as long as one line of code is added:
__metaclass__=type
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
Size=property (Getsize,setsize)
The property function creates an attribute where the accessor function is used as a parameter (first value, then Assignment), and this property is named size. This eliminates the need to worry about how it is implemented, and can handle width, height, and size in the same way.
[9.5.2] static methods and class member methods
Static methods and class member methods are loaded into objects of type Staticmethod and Classmethod, respectively, when they are created. The definition of a static method does not have a self parameter and can be called directly by the class itself. A class method requires a self-like parameter named CLS when it is defined, and a class member method can be called directly from a class's concrete object. However, the CLS parameter is automatically bound to the class.
Take a look at the following example:
__metaclass_=type
Class MyClass:
Def smeth ():
print ' This is a static method '
Semth=staticmethod (Smeth)
def cmeth (CLS):
print ' This is a class method of ', CLS
Cmeth=classmethod (Cmeth)
Techniques for manual packaging and replacement methods look a bit monotonous. A new syntax called adorners is introduced for such packaging methods (it is able to wrap any callable object, both for methods and functions). Using the @ operator, the adorner is listed above the method (or function) to create one or more adorners (the order in which multiple adorners are applied is the opposite of the order in which they were made).
__metaclass__=type
Class MyClass:
@staticmethod
Def smeth ():
print ' This is a static method '
@classmethod
def cmeth (CLS):
print ' This is a class method of ', CLS
Once these methods have been defined, they can be used as in the following example (No instantiation of the class in the example):
>>>myclass.smeth ()
This is a static method
>>>MYCLASS.CEMTH ()
This is a class method of <class ' __main__. MyClass ' >
Static methods and Class-member methods are not always important in python, and the main reason is that love can be replaced with a function or binding method.
[9.5.3] __getattr__, __setattr__ and their friends
It is possible to intercept all the properties of an object, and in order to execute code when accessing the attribute, some magical methods must be used.
__GETATTRIBUTE__ (self,name): called automatically when the attribute name is accessed.
__getattr__ (self,name): called automatically when the attribute name is accessed and the object does not respond to an attribute.
__setattr__ (Self,name,value): automatically called when attempting to assign a value to an attribute name
__delattr__ (self,name): called automatically when an attribute name is attempted to be deleted.
[9.6] Iterator
Only a special method __iter__ is discussed, which is the basis of the iterator rule.
[9.6.1] Iterator rules
Iteration means repeating things many times. You can actually iterate over other objects: the object that implements the __iter__ method.
The __iter__ method returns an iterator iterator, a so-called iterator that has an object that has the next method, which does not require any arguments at the time of the call. When the next method is called, the iterator returns its next value. If the next method is called, but the iterator has no value to return, a Stopiteration exception is thrown.
What is the key to iterative rules? Why is the list not applicable? Because the list is too lethal. If you have a function that calculates a value one by one, you might get a value when you use it---instead of getting all the values through the list at once. If there are many values, the list consumes too much memory. But there are other reasons: using Iterators is more general, simpler, and more elegant.
The "list" here is a Fibonacci sequence, using the following iterator:
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
Note that the iterator implements the __iter__ method, which actually returns the iterator itself. In many cases, __iter__ will be placed in other objects that will be used in the For loop. In this way, the program can return the desired iterator.
First, a Fibs object is generated:
>>>fibs=fibs ()
>>>for F in fibs:
If f>1000:
Print F
Break
[9.6.2] Getting a sequence from an iterator
In addition to iterating over iterators and iterative objects, you can convert them to sequences. A useful example of this is the use of the list construction method to explicitly convert an iterator to a list:
Class Testiterator:
Value=0
Def next (self):
Self.value+=1
If Self.value>10:raise stopiteration
Return Self.value
def __iter__ (self):
return self
>>>ti=testiterator ()
>>>list (TI)
[1,2,3,4,5,6,7,8,9,10]
[9.7] Generator
It and iterators are probably the most powerful two features introduced in recent years. However, the concept of generators is more advanced. To understand how it works and what it is useful for. The generator can help write very elegant code.
The generator is an iterator defined by a common function syntax. Let's look at how to create and use the generator, and then learn about its internal mechanisms.
[9.7.1] Create Builder
Creating a generator is as simple as creating a function. First, create a function that expands the nested list, and the argument is a list, and it looks like this:
NESTED=[[1,2],[3,4],[5]]
This is a list of lists. The function should print out the numbers in the list in order, and the workaround is as follows:
def flatten (nested):
For sublist in nested:
For element in sublist:
Yield element
Iterates through all the child lists in the nested list provided, and then iterates through the elements in the sub-list sequentially. The yield statement here is new knowledge. Any function that contains a yield statement is called a generator. In addition to its name, its behavior differs greatly from normal functions. This is because instead of returning a value like return, it produces more than one value at a time. Each time a value is ridden (using the yield statement), the function is frozen: that is, the function stops at that point and waits to be activated. When the function is activated, it executes from the point where it was stopped.
[9.7.2] Recursive generator
What if I want to handle nesting of any layer? For example, you might want to use to represent a tree structure. Each level of nesting requires a for loop to be added, but because it is not known that there are several layers of nesting, the workaround must be made more flexible, and it is time to turn to recursion.
def flatten (nested):
Try
Try:nested+ "
Except Typeerror:pass
Else:raise TypeError
For sublist in nested:
for element in Flatten (sublist):
Yield element
Except TypeError:
Yield nested
When flatten is called, there are two possibilities (most of the recursion is handled in two cases): the basic situation and the case where recursion is required.
[9.7.3] Universal generator
The generator is a function that contains the yield keyword, and when it is called, the code in the function weight is not executed, and an iterator is returned. Each time a value is requested, the code in the generator executes, knowing that a yield or return statement is encountered. The yield statement means that a value should be generated, and the return statement means that the generator will stop executing.
The generator consists of two parts: the generator's function and the generator's iterator. The function of the generator is defined by the DEF statement, which contains the portion of yield, and the iterator of the generator is the part returned by this function. Two entities are often treated as one, and together they are called generators.
[9.7.4] Generator method
[9.7.5] Simulation generator
[9.8] Question of the eight Queens
Describes how to use the Builder to solve classic programming problems.
[9.8.1] Generator and backtracking
Generators are the ideal implementation tool for complex recursive algorithms that produce results gradually. Without a generator, the algorithm requires a semi-finished solution with additional parameters for the seat, so that recursive invocation can be established on this scheme. If the generator is used, then all recursive calls are created with their own yield portion. The same strategy can also be used in traversing graphs and tree structures.
In some applications, the answer must be chosen many times before it can be reached. And the program is not just on one level but has to make a choice at every level of recursion. Take the example of life, first imagine you want to attend a very important memory, but you do not know where to meet, there are two doors in front of you, the meeting place in one of the doors, so someone picked the left entrance, and then found two doors. Then chose the left door, the result is wrong, so go back to just two door there, and choose the right door, the result is still wrong, so again backtracking, know to return to the beginning point, and then where to choose the right door.
Such backtracking strategies are useful in solving the problem of having to try each combination, knowing that a solution is found. This type of problem can be solved in the following pseudo-code:
# Pseudo-code
1th level of all possibilities:
2nd level of all possibilities:
......
The possibility of all the nth layers:
Is it possible?
In order to use the For loop directly, it is necessary to know the exact number of layers to be encountered, and if the layer information is not available, recursion can be used.
[9.8.2] Questions
This is a favorite computer science puzzle: There is a chessboard and 8 queens to put on top. The only requirement is that the Queen cannot form a threat. In other words, they must be placed in a state where every queen cannot eat the other queens. How do you do that? How can the Queen be placed?
This is a typical backtracking problem: first try to place the 1th queen, then try the 2nd one, and so on. If you find that you cannot place the next queen, go back to the previous step and try to put the Queen in another position. Finally, either try out all the possibilities or find a solution.
The question tells us that there are only 8 queens on the board, but we assume that there are any number of Queens (which is more in line with real-life backtracking problems). For a more efficient solution to this problem, you can view http://www.cit.gu.edu.au/~sosic/nqueens.html to find a brief introduction to the various solutions.
[9.8.3] Status indication
To represent a possible solution, you can use tuples. The elements in each tuple indicate the location of the queen of the corresponding row. If state[0]==3. Then the 1th line of the Queen is in column 4th. When at a recursive level, you can only know the position of the previous row of Queens, so you need a status tuple (or less than the number of Queens) with a length of less than 8.
It is also possible to use lists instead of tuples to represent states. The specific use of which is only a matter of habit. In general, tuples are a good choice if the sequence is small and static.
[9.8.4] Looking for conflict
The first choice starts with some simple abstractions. In order to find a setting that does not conflict (no queen will be eaten by other queens), you must first define what the conflict is.
The location of the known Queen is passed to the conflict function, and then the function determines whether the next Queen's position will have a new conflict:
def conflict (STATE,NEXTX):
Nexty=len (state)
For I in Range (nexty):
If ABS (STATE[I]-NEXTX) in (0,nexty-i):
Return True
Return False
The parameter nextx represents the next queen's horizontal position (x-coordinate or column), and nexty represents the vertical position (y-coordinate or line). This function makes a simple check of the position of each of the previous queens. If the next queen has the same horizontal position as the previous queen, or if it is on the same diagonal, a conflict will occur, followed by a return of true. If no such conflict occurs, then returning false is not easy to understand is the following expression:
ABS (STATE[I]-NEXTX) in (0,nexty-i)
If the next queen and the previous queen are considering the horizontal distance of 0 (the same column) or equal to the vertical distance (on a diagonal) returns true, otherwise false.
[9.8.5] Basic situation
The implementation of the eight Queens problem is a little bit too good to implement, but it's not hard to use a generator. If you are not accustomed to using recursion, then it is best not to solve this entire yourself. It is important to note that this solution is not very efficient, so if the Queen has a lot of numbers, it will be a bit slow to run.
Start with the basic situation: the last Queen. What do you want it to do? Suppose you want to find out all the possible solutions, so that it can generate all the positions it can occupy based on the location of the other queens. Can describe such a situation directly.
def Queens (Nums,state):
If Len (state) ==num-1:
For POS in range (num):
If not conflict (State,pos):
Yield POS
Described in human language, it means: if there is only one queen left to lay. So it is convenient for all possible locations, and returns no conflict where it occurred. The num parameter is the total number of Queens. The state parameter is a tuple that has the location information of the preceding Queens.
[9.8.6] The case of recursion is required
Now let's look at the recursive parts of the solution. After the basic situation is completed, the recursive function will be the result from the lower level of jiading (through induction) is correct. So what needs to be done is to add the ELSE clause to the IF statement in the implementation of the preceding Queen function.
So what happens to recursive calls? You want to get all the lower queens, right? Assume that the location information is returned as a tuple. In this case, you need to modify the basic condition and return a tuple.
In this way, the program gets a tuple containing the location information from the previous queen, and provides each of the current queen's valid location information for the Empress. To keep the program running, the next thing to do is to add the current location information to the tuple and pass it to the queen behind.
...
Else
For POS in range (num):
If not conflict (State,pos):
For result in Queens (Num,state+ (POS)):
Yield (POS,) +result
The for POS and if not conflict sections are the same as the previous code, so you can simplify the code a little bit. Add some default parameters.
def Queens (Num=8,state= ()):
For POS in range (num):
If not conflict (State,pos):
If Len (state) ==num-1:
Yield (POS,)
Else
For result in Queens (Num,state+ (POS)):
Yield (POS,) +result
Generator quees can give all the solutions (that is, all the legal ways to place the Queen):
>>>list (Queens (3))
[]
>>>for Solution in Queens (8):
Print Solution
>>>len (Queens (8))
92
If you use 8 queens to run Queens, there are 92 options.
[9.8.7] Packaging
Try to make the output easier to understand before ending the eight Queens question. Cleaning out the output is always a good habit, because it is easy to find errors.
def prettyprint (solution):
def line (Pos,length=len (solution)):
Return '. ' * (POS) + ' X ' + '. ' * Len (length-pos-1)
For POS in Solution:
Print Line (POS)
Note that a small helper function is created in Prettyprint, which is placed inside the prettyprint because the door is assumed to be unused anywhere outside.
[9.9] Summary
A number of magical methods are described below to summarize:
Legacy and Modern classes: create modern classes that directly or indirectly subclass object. Or you can set the __metaclass__ property.
Magic Method:Python has some special methods (the name begins and ends with a double underscore). These methods and functions are only very small differences, but most of the methods are automatically called by Python in some cases (such as __init__ when an object is created).
Construction Methods: This is common to object-oriented languages, and you might want to implement a construction method for each class that you write. The construction method is named __init__ and is automatically called immediately after the object is created.
rewrite: A class can implement methods to override these methods and tree shapes defined in its superclass. If the new method calls the overridden version of the method, you can call the unbound version directly from the superclass or use the Super function.
sequences and mappings: creating your own sequences or mappings requires methods that implement all the sequence and mapping rules, including __getitem__ and __setitem__, which are special methods. The subclass list and dict can save a lot of work.
iterator: An iterator is a simple object with the next method. Iterators can iterate over a series of values. The next method throws an stopiteration= exception when there is no value available for iteration. An iterative object has a __iter__ method that returns an iterator that can be used in a for loop like a sequence. In general, the iterator itself is iterative, that is, the iterator has a next method that returns its own.
generator: the Generator function (or method) is a function that contains the keyword yield. When called, the generator function returns a generator. You can use the send, throw, and close methods to interact with the activity builder and the outside world.
eight Queen's problem: using generators can be easily resolved. The question describes how to place 8 queens on a chessboard so that they do not attack each other.
Basic Python Tutorial "reading notes"-2016/7/24