Article directory
- 1, Duck type and polymorphism
- 2, Abstract base class (abc module)
- 3, Two pairs of concept discrimination
- 4, Search order and introspection mechanism of MRO algorithm
- 1.MRO algorithm
- (1) Algorithm before Python 2.2: Jindian class
- (2) After Python 2.2, BFS (breadth first search) was introduced
- (3) After Python 2.3, python uses the C3 algorithm
- 2. Introspection mechanism
- 5, super function
1, Duck type and polymorphism
The concept of polymorphism is applied to strongly typed languages such as Java and C, while Python advocates "duck type".
When a dynamic language calls an instance method, it does not check the type. As long as the method exists and the parameters are correct, it can be called. This is the "duck type" of dynamic language, which does not require strict inheritance system. As long as an object "looks like a duck and walks like a duck", it can be regarded as a duck.
a = [1,2] b = [3,4] c = (5,7) d = {7,8} a.extend(b) print(a) for item in c: print(item)
Printing
[1, 2, 3, 4] 5 7
The source code of extend(self,iterable) method is
def extend(self, *args, **kwargs): # real signature unknown """ Extend list by appending elements from the iterable. """ pass
There is no concrete code, the bottom layer is encapsulated in C language.
iterable:
for the object that can be iterated.
The parameters of the extend method are iteratable objects, so lists, tuples, and sets can be used as parameters of the extend method.
a = [1,2] b = [3,4] c = (5,7) d = {7,8} a.extend(c) print(a) b.extend(d) print(b)
Printing
[1, 2, 5, 7] [3, 4, 8, 7]
Polymorphism:
The type of the definition time is not the same as the type of the runtime, which becomes polymorphic.
class Cat(object): def say(self): print('I am a cat') class Dog(object): def say(self): print('I am a dog') class Duck(object): def say(self): print('I am a duck') animal_list = [Cat, Dog, Duck] for animal in animal_list: animal().say()
Printing
I am a cat I am a dog I am a duck
2, Abstract base class (abc module)
1. definition
Abstract base class (ABC):
Abstract base class is a class in which pure virtual member functions are defined. The pure virtual function only provides the interface, and has no concrete implementation.
In other words, an abstract base class is a class that defines various methods without specific implementation. Any class that inherits from the abstract base class must implement these methods, otherwise it cannot be instantiated.
Characteristic:
- Abstract base classes cannot be instantiated (objects cannot be created), usually as base classes for subclasses to inherit (cannot be instantiated);
- The virtual function is rewritten in the subclass to implement the specific interface (the method must be rewritten in the subclass).
2. Application scenario
Determine the type of an object
For example: Sized determines whether a class implements the \\\\\\\\.
from collections.abc import Sized class Demo(object): def __init__(self,name): self.name = name def __len__(self): #Magic method, can only use len() method after joining return len(self.name) def test(self): pass d = Demo(['Tom','Jack']) print(len(d)) #The hasattr() method is used to determine whether an object has a method print(hasattr(d,'__len__')) print(hasattr(d,'test')) print(isinstance(d,Demo)) print(isinstance(d,Sized))
Printing
2 True True True
Forcing a subclass to implement certain methods
A mandatory subclass must implement a method:
class CacheBase(object): def get(self, key): pass def set(self, key, value): pass class RedisBase(CacheBase): pass r = RedisBase() r.get('Tom')
Method 1: throw an exception in the parent method
class CacheBase(object): def get(self,key): # pass raise ValueError def set(self,key,value): # pass raise NotImplementedError class RedisBase(CacheBase): pass r = RedisBase() r.get('Tom')
Error will be reported during operation
Traceback (most recent call last): File "xxx/demo.py", line 89, in <module> r.get('Tom') File "xxx/demo.py", line 79, in get raise ValueError ValueError
Override methods in the parent class:
class CacheBase(object): def get(self,key): # pass raise ValueError def set(self,key,value): # pass raise NotImplementedError class RedisBase(CacheBase): # pass #Override method in parent class def get(self,key): pass r = RedisBase() r.get('Tom')
Run again without error.
Method 2: the parent class inherits the abstract base class and the method is decorated with a decorator
The parent class inherits the abstract base class so that the child class must inherit all the abstract methods specified by the parent class.
import abc class CacheBase(metaclass=abc.ABCMeta): @abc.abstractmethod def get(self,key): pass # raise ValueError @abc.abstractmethod def set(self,key,value): pass # raise NotImplementedError class RedisBase(CacheBase): #Override method in parent class def get(self,key): pass r = RedisBase() r.get('Tom')
Error will be reported during operation
Traceback (most recent call last): File "xxx/demo.py", line 94, in <module> r = RedisBase() TypeError: Can't instantiate abstract class RedisBase with abstract methods set
After the subclass inherits all the methods of the parent class
import abc class CacheBase(metaclass=abc.ABCMeta): @abc.abstractmethod def get(self,key): pass # raise ValueError @abc.abstractmethod def set(self,key,value): pass # raise NotImplementedError class RedisBase(CacheBase): #Override method in parent class def get(self,key): pass def set(self,key,value): pass r = RedisBase() r.get('Tom')
Run again without error.
The parent method with decorator @ abc.abstractmethod must be overridden by the child class inheritance.
3, Two pairs of concept discrimination
1.isinstance and type
i = 1 s = 'hello' print(isinstance(i,int)) print(isinstance(s,int)) print(isinstance(s,str))
Printing
True False True
The isinstance() method considers the inheritance relationship of the class.
class A(object): pass class B(A): pass b = B() print(isinstance(b,B)) print(isinstance(b,A))
Printing
True True
type() does not consider the inheritance relationship of the class.
class A(object): pass class B(A): pass b = B() print(type(b) is B) print(type(b) is A)
Printing
True False
2. Class and object variables
Class properties can be found up, instance properties cannot be found down.
class A: #Class attribute aa = 1 #Example method def __init__(self,x,y): #Instance attribute self.x = x self.y = y a = A(1,2) print(a.x,a.y,a.aa) try: print(A.x) except Exception as e: print(e.args[0]) A.aa = 11 #Equivalent to increasing self.aa = 22 when instantiating a.aa = 22 print(a.aa) print(A.aa) b = A(1,2) print(b.aa)
Printing
1 2 1 type object 'A' has no attribute 'x' 22 11 11
4, Search order and introspection mechanism of MRO algorithm
1.MRO algorithm
class A(object): name = 'Corley' def __init__(self): self.name = 'cl' a =A() print(a.name) print(A.name)
Printing
cl Corley
(1) Algorithm before Python 2.2: Jindian class
DFS(deep first search): A->B->D->C->E
class D(object): pass class B(D): pass class E(object): pass class C(E): pass class A(B,C): pass print(A.__mro__)
Printing
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
The order is a - > b - > D - > C - > e - > object.
(2) After Python 2.2, BFS (breadth first search) was introduced
BFS:A->B->C->D
class D(object): pass class B(D): pass class C(D): pass class A(B,C): pass print(A.__mro__)
Printing
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
The order is a - > b - > C - > D - > object.
(3) After Python 2.3, python uses the C3 algorithm
C3 algorithm of Python's new class inheritance: https://www.cnblogs.com/blackmatrix/p/5644023.html.
2. Introspection mechanism
Introspection is to query the internal structure of an object through a certain mechanism.
The common introspection mechanisms (function usage) in Python are:
dir(),type(), hasattr(), isinstance().
Through these functions, we can know the type of the object, judge whether there is a property in the object and access the property of the object when the program is running.
class Person(object): name = 'Corley' class Student(Person): def __init__(self,school_name): self.school_name = school_name user = Student('CUFE') #__dict does not include parent properties print(user.__dict__) print(user.name) print(dir(user))
Printing
{'school_name': 'CUFE'} Corley ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_name']
Again as
a = [1,2] try: print(a.__dict__) except Exception as e: print(e.args[0]) print(dir(a)) print(list.__dict__)
Printing
'list' object has no attribute '__dict__' ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] {'__repr__': <slot wrapper '__repr__' of 'list' objects>, '__hash__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>, '__lt__': <slot wrapper '__lt__' of 'list' objects>, '__le__': <slot wrapper '__le__' of 'list' objects>, '__eq__': <slot wrapper '__eq__' of 'list' objects>, '__ne__': <slot wrapper '__ne__' of 'list' objects>, '__gt__': <slot wrapper '__gt__' of 'list' objects>, '__ge__': <slot wrapper '__ge__' of 'list' objects>, '__iter__': <slot wrapper '__iter__' of 'list' objects>, '__init__': <slot wrapper '__init__' of 'list' objects>, '__len__': <slot wrapper '__len__' of 'list' objects>, '__getitem__': <method '__getitem__' of 'list' objects>, '__setitem__': <slot wrapper '__setitem__' of 'list' objects>, '__delitem__': <slot wrapper '__delitem__' of 'list' objects>, '__add__': <slot wrapper '__add__' of 'list' objects>, '__mul__': <slot wrapper '__mul__' of 'list' objects>, '__rmul__': <slot wrapper '__rmul__' of 'list' objects>, '__contains__': <slot wrapper '__contains__' of 'list' objects>, '__iadd__': <slot wrapper '__iadd__' of 'list' objects>, '__imul__': <slot wrapper '__imul__' of 'list' objects>, '__new__': <built-in method __new__ of type object at 0x00007FFDDE682D30>, '__reversed__': <method '__reversed__' of 'list' objects>, '__sizeof__': <method '__sizeof__' of 'list' objects>, 'clear': <method 'clear' of 'list' objects>, 'copy': <method 'copy' of 'list' objects>, 'append': <method 'append' of 'list' objects>, 'insert': <method 'insert' of 'list' objects>, 'extend': <method 'extend' of 'list' objects>, 'pop': <method 'pop' of 'list' objects>, 'remove': <method 'remove' of 'list' objects>, 'index': <method 'index' of 'list' objects>, 'count': <method 'count' of 'list' objects>, 'reverse': <method 'reverse' of 'list' objects>, 'sort': <method 'sort' of 'list' objects>, '__doc__': 'Built-in mutable sequence.\n\nIf no argument is given, the constructor creates a new empty list.\nThe argument must be an iterable if specified.'}
It is easy to know that the list does not have a dict attribute, and the list object has a dict attribute.
5, super function
In class inheritance, if a method is redefined, it will overwrite the method with the same name of the parent class.
But sometimes, we want to realize the function of the parent class at the same time. At this time, we need to call the method of the parent class, which can be realized by using super.
class A(object): def __init__(self): print('A') class B(A): def __init__(self): print('B') #Inherit the parent method and print out A super().__init__() #Super (B, self) in Python 2 b = B()
Printing
B A
Reflection:
Why override B's constructor and call super?
class People(object): def __init__(self,name,age,weight): self.name = name self.age = age self.weight = weight def speak(self): print('%s says: I\'m %d years old'%(self.name,self.age)) class Student(People): def __init__(self,name,age,weight,grade): super().__init__(name,age,weight) self.grade = grade s = Student('Tom',18,30,3) s.speak()
Printing
Tom says: I'm 18 years old
Or you can use the parent class name to initialize the child class, and you need the self parameter.
class People(object): def __init__(self,name,age,weight): self.name = name self.age = age self.weight = weight def speak(self): print('%s says: I\'m %d years old'%(self.name,self.age)) class Student(People): def __init__(self,name,age,weight,grade): People.__init__(self,name,age,weight) self.grade = grade def speak(self): print('%s says: I\'m %d years old, and I\'m in grade %d' % (self.name, self.age,self.grade)) s = Student('Tom',18,30,3) s.speak()
Printing
Tom says: I'm 18 years old, and I'm in grade 3
Conclusion:
super is called to:
Save instantiation parameter code and avoid attributes;
Extended properties.
What is the order of super execution?
class A(object): def __init__(self): print('A') class B(A): def __init__(self): print('B') super().__init__() class C(A): def __init__(self): print('C') super().__init__() class D(B,C): def __init__(self): print('D') super().__init__() d = D() print(D.__mro__)
Printing
D B C A (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Conclusion:
super calls the methods in the parent class not according to the general method, but according to the MRO algorithm, which is also the order of the MRO algorithm.
Again as
class A(object): def __init__(self): print('A') class B(A): def __init__(self): print('B') super().__init__() class C(A): def __init__(self): print('C') super().__init__() class E(object): def __init__(self): print('E') class D(B,C,E): def __init__(self): print('D') super().__init__() d = D() print(D.__mro__)
Printing
D B C A (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.E'>, <class 'object'>)