Contents
1. Preface
In Python, some names are spelled in a peculiar manner, with two leading and two trailing underscores which signals that the name has a special significance—you should never invent such names for your own programs
. And this kind of methods are called magic methods
.
2. Constructor __ init __
- A constructor is an initializing method of a class which will be called automatically right after the object has been created.
class foobar:
def __init__(self):
self.somevar=42
fb=foobar()
fb.somevar
>>>42
- You can give arguments to __init__ method
class foobar_2:
def __init__(self,value):# with argument
self.somevar=value
fb2=foobar_2(42)# set the argument
fb.somevar
>>>
42
3. super function
- In inheritance, the __init__ of the subclass will
overide
that of the superclass, andlose
some attributes of superclass.
class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
ptint('It needs to eat')
self.hungry=False
else:
print('NO,thanks!')
class SongBird(Bird):
def __init__(self):
self.sound='Squawk'
def sing(self):
print(self.sound)
sb=SongBird()
sb.eat()
>>>
--------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-11-8dc456f39f61> in <module>()
1 sb=SongBird()
----> 2 sb.eat()
<ipython-input-10-469072ddb6f8> in eat(self)
3 self.hungry=True
4 def eat(self):
----> 5 if self.hungry:
6 ptint('It needs to eat')
7 self.hungry=False
AttributeError: 'SongBird' object has no attribute 'hungry'
SongBird class has attribute eat(), but does not have attribute hungry, because the __init__ of SongBird override the __init__ of Bird
- Use
super().\_\_init__()
without any argument to solve the problem.
class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print('It needs to eat')
self.hungry=False
else:
print('NO,thanks!')
class SongBird(Bird):
def __init__(self):
super().__init__() # bind the __init__ of superclass
self.sound='Squawk'
def sing(self):
print(self.sound)
sb=SongBird()
sb.eat()
>>>
It needs to eat
super().method() can bind any methods in the superclass to methods in subclass
3. Protocol of Python
- The word protocol is often used in Python to describe the rules governing some form of behavior. This is somewhat similar to the notion of interfaces mentioned in Chapter 7. The protocol says something about which methods you should implement and what those methods should do. Because polymorphism in Python is based on only the object’s behavior (and not on its ancestry, for example, its class or superclass, and so forth), this is an important concept: where other languages might require an object to belong to a certain class or to implement a certain interface, Python often simply requires it to follow some given protocol. So, to be a sequence, all you have to do is follow the sequence protocol.
protocol methods: __name__
: With some protocol methods, you can exert some corresponding operations on the class’ instance, and these oprations will automatically call the protocol methods.
4. The Basic Sequence and Mapping Protocol
-
Sequences and mappings are basically collections of items.
-
They have some protocol methods, and every protocol corresponds to a certain operation on the sequences or mappings
-
To implement their basic behavior (protocol),you need
two
magic methods if your objects areimmutable
, orfour
if they aremutable
. These are all attributes for sequence class, the behaviors a sequence should have.-
__ len__(self): This method should return the number of items contained in the collection.
=>len()
-
__ getitem__(self, key): This should return the value corresponding to the given key.
=>list[n],dict[key]
-
__ setitem__(self, key, value): This should store value in a manner associated with key, so it can later be retrieved with __ getitem__.
=>list[n]=x, dict[key]=y
-
__ delitem__(self, key): This is called when someone uses the __ del__ statement on a part of the object and should delete the element associated with key.
=>del()
-
-
Some
extra requirements
are imposed on these methods.- For a sequence, if the key is a negative integer,
it should be used to count from the end. In other words
, treat x[-n] the same as x[len(x)-n]. - If the key is of an inappropriate type (such as a string key used on a sequence), a TypeError may be raised.
- If the index of a sequence is of the right type, but outside the allowed range, an
IndexError should be raised.
- For a sequence, if the key is a negative integer,
5. Example: Creat a Infinite Sequence
- This implements an arithmetic sequence—a sequence of numbers in which each is greater than the previous one by a constant amount. The first value is given by the constructor parameter start (defaulting to zero), while the step between the values is given by step (defaulting to one). You allow the user to change some of the elements by keeping the exceptions to the general rule in a dictionary called changed. If the element hasn’t been changed, it is calculated as self.start + key * self.step.
def check_index(key):
"""
Is the given key an acceptable index?
To be acceptable, the key should be a non-negative integer. If it
is not an integer, a TypeError is raised; if it is negative, an
IndexError is raised (since the sequence is of infinite length).
"""
if not isinstance(key,int):
raise TypeError
if key<0:
raise IndexError
class ArithmeticSequence:
def __init__(self,start=0,step=1):
"""
Initialize the sequence
"""
self.start=start
self.step=step
self.changed={}
def __getitem__(self,key):
"""
get a value from the sequence
"""
check_index(key)
try:
return self.changed[key]
except :
return self.start+key*self.step
def __setitem__(self,key,value):
check_index(key)
self.changed[key]=value
a_s=ArithmeticSequence()
a_s[15]
>>>
15
a_s[15]=24
a_s[15]
>>>
24
-
It is impotant to figure out the actions of a class before you creat it, and the actions are the basics to construct a class.
-
The class name of integer object is int.
-
With the protocol methods implemented in the class, some sequence operations can be used on the class.
6. The property function
property(fget,fset,fdel,doc)
: Taking accessors as parameters( getter first, then setter, the next is deletor, the final is docstring) so that the attribute will have certain properties corresponding to accessors. It is to call the corresponding accessor method when conduct a property. You can use either positional parameters or keyword parameters when using property().
class Rectangle:
def __init__(self,width,height):
self.width=width
self.height=height
def get_size(self):
return self.width, self.height
def set_size(self,size):
self.width,self.height=size
size=property(get_size,set_size)
r=Rectangle(10,15)
r.size # call the corresponding accessor get_size which returns a tuple
>>>
(10, 15)
r.size=(100,150)
r.size
>>>
(100, 150)
Because that the size only contains the getter and the setter, so it can only be read or written.
Because when you use the properties of size, it will call the the getter and the setter, so you will get the returns of getter, and when you assign values to size, the form of value must accord with the form of setter’s parameter which is a tuple.
7. Static Methods and Class Methods
- Static Methods and Class Methods are methods can be used directly by class withou instantializing the class.
- It can be defined like this:
class MyClass:
@staticmethod
def smeth():
print('This is a static method.')
@classmethod
def cmeth(cls):
print('This is a class method of',cls)
MyClass().smeth()
MyClass().cmeth()
>>>
This is a static method.
This is a class method of <class '__main__.MyClass'>
Static methods are defined without self arguments, and they can be called directly on the class itself.
Class methods are defined with a self-like parameter normally called cls. You can call class methods directly on the class object too, but the cls parameter then automatically is bound to the class.
8. Iterators
- The iterator protocol: to iterate means to repeat something several times. In addtion to sequences and dictionaries, you can iterate over other objects------objects that implement the
__ iter__
method. - The
__ iter__
method returns aniterator
, which isany object with a method called __ next__
, which is callable without any arguments. - When you call the __ next__ method,
the iterator should return its “next value.” If the method is called and the iterator has no more values to return, it should raise a StopIteration exception
.
class Fib:
def __init__(self):
self.a=0
self.b=1
def __iter__(self):
return self
def __next__(self):
self.a,self.b=self.b,self.a+self.b
return self.a
fibs=Fib()
for f in fibs:
if f<1000:
print(f)
>>>
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
To make a class Fibs which can be iterated, this class should have a method __ iter__
which returns the iterator object (Fibs itself in this case)
, this iterator object ( Fibs itself in this case) shoud have the __ next__
method to return the next value of the object
.
- In many cases, you would put the iter method in another object, which you would use in the for loop. That would then return your iterator.
It is recommended that iterators implement an __iter__ method of their own in addition (returning self, just as I did here), so they themselves can be used directly in for loops
.
9. What to do rather than what it is
When you construct a class, pay attention to the performances you want the object to have. The main work should be to construct method corresponding to the performances. For example, in the Fibs example, you want the object to be iterated, you just implement iterator protocols, and if you want the object to have the performances of sequence ( like read by index) ,just implement sequence protocol methods.
10. iter() and next()
iter()
: the built-in function iter()
can return a iterator object of a iterable object
.
next()
: the built-in function next()
return the next value of the iterator object
.