Python polymorphism and duck types
In Python, object orientation: Different objects behave differently when they receive the same method or function. That is, each object can respond to a common function in its own way, and different ways can achieve different results.
There are two preconditions to realize polymorphism: 1. Inheritance: between subclass and parent class; 2. 2. Override: a method or function of the parent class
If you still have doubts, take a look at the following example to further understand:
def __init__(self,name,area,type): self.name=name self.area=area self.type=type def go_home(self): Print ('%s '%s '% (self.name,self.area)) elif self.type == 'black ': Print ('%s' return %s' %(self.name,self.area)) elif self.type == 'white ': Print ('%s '%s '% (self.name,self.area)) elif self.type == 'blue ': print('%s '%s '% (self.name,self.area)) else: Print (Person) class Melanoderm(Person): pass class Yellow(Person): pass class White(Person): M = Melanoderm pass # define different objects (' Rose ', 'Africa', 'black') Y = Yellow (' Alert ', 'us',' White ') W = White (' Ming ', 'China', 'Yellow') # different object to realize the same function method, Def func(obj): obj.go_home() func(M) func(Y) func(W)Copy the code
Rose wants to go back to Africa. Xiao Ming wants to go back to China
Speaking of which, do you have any questions about polymorphism? Why use polymorphism?
1. Increased the flexibility of the program, users are in the same form to call, such as func(obj).
2. Increased the program scalability, by inheriting the Person class to create a new class, users do not need to change their own code, or use func(obj) to call.
Let’s add an instantiation object to the original base code and see if the call method has changed.
class Person: def __init__(self,name,area,type): self.name=name self.area=area self.type=type def go_home(self): Print ('%s '%s '% (self.name,self.area)) elif self.type == 'black ': Print ('%s' return %s' %(self.name,self.area)) elif self.type == 'white ': Print ('%s '%s '% (self.name,self.area)) elif self.type == 'blue ': print('%s '%s '% (self.name,self.area)) else: Print (Person) class Melanoderm(Person): pass class Yellow(Person): pass class White(Person): pass class Blue(Person): # increase species pass in the form of a M = # define different objects Melanoderm (' Rose ', 'Africa', 'black') Y = Yellow (' Alert ', 'us',' White ') W = White (' Ming ', 'China', 'Yellow') # add a class object Def func(obj): obj. Go_home () func(M) func(Y) func(W)Copy the code
When you add a form, it doesn’t affect how the external user calls it. It is transparent to the user. You only need to modify the class code internally to implement it.
And what is a “duck type”?
Dynamic languages call instance methods without checking the type, as long as the method exists and the parameters are correct, it can be called. This is the “duck type” of dynamic languages. It does not require a strict inheritance system, and an object can be considered a duck as long as it “looks like a duck and walks like a duck.”
Here’s an example:
Def info(self): print(' I am Cat ') class Dog(object): def info(self): print('i am dog') class Duck(object): def info(self): print('i am duck') animal_list = [Cat, Dog, Duck] for animal in animal_list: Animal ().info() = animal().info()Copy the code
Note: Cat and Dog are listed before the duck type is run, as variables. When run, add () and call info() to make it clear that Cat is a class
Abstract base classes
Abstract Base class (ABC) : An abstract base class is a class in which pure virtual member functions are defined. Pure virtual functions only provide interfaces, and no concrete implementation; Abstract base classes cannot be instantiated (objects cannot be created) and are usually inherited by subclasses that override virtual functions to implement concrete interfaces.
In short, an abstract base class is a class that defines methods without implementing them, and any class that inherits from an abstract base class must implement those methods before it can be instantiated.
2.1 What are the application characteristics of abstract base classes?
2. Emphasize that a subclass must implement certain methodsCopy the code
2.1.1 Check whether a method exists in a class
- Define a Demo class that contains __len__ magic methods
- Import the Sized class in the abstract base class
Class Demo(object): def __init__(self, li): self. Li = li def __len__(self): return len(self.li) l = ['c', 'chen', 'wu'] d = Demo(l) # print(d) # print the address of the Demo object <__main__.Demo object at 0x0000025821DBA1D0> # print(len(d)) # # print(hasattr(d,'__len__')) # print(hasattr(d,'__len__')) # print(hasattr(d,'__len__')) # Return True to view the source code for "" ever Sized ", "ever Sized", and then for any object class that has a __len__ method "" from collections.abc import Sized # Sized The class print(isinstance(d, Sized)) # True specifies that d is of type SizedCopy the code
【 extension 】 : View the Sized source code
class Sized(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __len__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
return _check_methods(C, "__len__")
return NotImplemented
Copy the code
The Sized class encapsulates a magic __len__ method that is an abstract class method
2.1.2 Enforce methods that subclasses must implement
Here’s an example to understand this feature:
Class CacheBase(object): def dele(self): raise NotImplementedError def creat(self): raise NotImplementedError class RedisBase(CacheBase): """ 1. Def creat(self): print(' JSJCD ') r = RedisBase() r.creat() r.dele(Copy the code
[note] : This is a normal override call, from the base class object, r.ele () method does not override the parent method, so it will directly report an error
How is an abstract base class implemented?
""" force subclasses to override method 2 abstract base class implementation """ import ABC # note: ABC.ABCMeta class CacheBase(metaclass= ABC.ABCMeta) @abc.abstractmethod def dele(self): print('dele') def creat(self): print('creat') class RedisBase(CacheBase): def dele(self): print('adgj') def creat(self): print('asdd') r= RedisBase() r.creat() # r.dele()Copy the code
[note] : @abc. abstractMethod is required when the parent class defines a method, otherwise an exception will be raised when the subclass calls it.
Type and isinstance
There are two main differences between the two:
- Type does not consider inheritance
- Isinstance considers inheritance
Here’s a simple example:
Print (isinstance(b, int, STR)) print(isinstance(b, int, STR)) print(type(b)Copy the code
Then look at the following example to understand the difference between the two for inheritance:
Class Father(object): pass class Son(Father): pass ls = Son() # print(isinstance(ls,Son)) # True # print(isinstance(ls, Father) # True print(type(ls) is Son) # True print(type(ls) is Father) # FalseCopy the code
【 Summary 】 : From the above examples, it can be found that isinstance considers the inheritance relationship, while type does not consider the inheritance relationship, the default is two classes.
4. The relationship between class attributes and instance attributes
4.1 What is the difference between the two?
Since Python is a dynamic language, an instance created from a class can bind attributes arbitrarily. The way to bind attributes to an instance is through the instance variable, or through the self variable:
Class Student(object): def __init__(self, name): # class Student(object): def __init__(self, name): #Copy the code
But what if the Student class itself needs to bind a property? You can define attributes directly in class, which are class attributes and are owned by the Student class:
class Student(object):
name = 'Student'
Copy the code
When we define a class property, is it accessible to all instances of the class, even though the property is classified as owned?
>>> class Student(object): ... name = 'Student' ... >>> s = Student() >>> print(s.name) Student >>> print(Student. Name) # print(Student. Name) class name Student >>> s.name = 'Michael' Michael >>> print(student.name) # print(s.name) # print(s.name) # Student >>> print(s.name) # print(s.name) The name property of the class shows up as StudentCopy the code
In the example above, attributes of the class can be found, and instances can be accessed, but if there are attributes in the instance, instance attributes are preferentially taken.
Here’s an extension of the search order:
1. The object can be looked up, so it can access the class attribute. • When the object has the instance attribute, it outputs its own 2. Classes cannot look down, so only class attributes can be accessedCopy the code
【 Summary 】 :
- Instance attributes belong to each instance and do not interfere with each other.
- Class attributes are class-owned, and all instances share one attribute;
- Do not use the same name for instance attributes and class attributes, or you will generate hard-to-find errors.
4.2 What is the search order of multiple inheritance?
For example, what is the order in which multiple inheritance relationships are found?
Here will involve a classical algorithm: MRO algorithm, DFS(Deep first Search) depth first, its search order will be as follows: first left and then right
But what about the order of lookup if it’s diamond inheritance?
Here we introduce BFS(breadth first), which looks in the following order:
Here’s a simple example:
Class D(object): Pass class B(D): pass class C(D): Pass class A(B, C): For pass # and order (< class '__main__. A' >, < class '__main__. B' >, < class '__main__. C' >, < class '__main__. D' >, <class 'object'>) # print(a.__mro__)Copy the code
Python object introspection mechanism
Some of the more common mechanisms for introspection in Python (function usage) are: Dir (), type(), hasattr(), isinstance(). Through these functions, the program can know the type of the object, determine whether the object has an attribute, and access the attribute of the object.
Class Person(object): name ='chem' class Student(Person): def __init__(self,school_name): Self. School_name = school_name Chen = Student(' school_name ') print(Chen.__dict__) # print(dir(Chen)) # [] View properties and methodsCopy the code
More than a simple example, if want to know about other introspection mechanism, can refer to this link: www.cnblogs.com/ArsenalfanI…
The super function
Let’s look at a simple use of the super function:
Class A(object): def __init__(self): print(' A ') class B(A): def __init__(self): print('b') super().__init__() b = B() print(b)Copy the code
This is a single inheritance. This run outputs both B and A.
But what about multiple inheritance?
class A(object):
def __init__(self):
print("A")
class C(A):
def __init__(self):
print("B")
super().__init__()
class B(A):
def __init__(self):
print("C")
super().__init__()
class D(B,C):
def __init__(self):
print("D")
super().__init__()
if __name__ == '__main__':
d = D()
Copy the code
You can see the inheritance order by printing print(d.ro) as follows:
(<class ‘main.D’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.A’>, <class ‘object’>)