Deep Mining of Python classes and meta classes I [experience] and deep mining of python
The previous article introduced the standard library of Python enumeration types. In addition to its practicality, there is also an important reason that its implementation process is an example of a good learning and understanding of Python classes and meta classes. So the next two articles will take this as an example to explore the mechanisms behind classes and meta classes in Python.
After opening any Python tutorial, you can see the following two sentences at a certain position:
Everything in Python is an object (Everything in Python is an object );
Python is an Object-Oriented Programming (OOP) language.
Although in the context of the above two sentences, the meaning of objects may be slightly different, but it is certain that objects have very important significance in Python, it is also the basis of all the content we will discuss next. So what is the object?
Object)
Objects are an abstraction of data in Python. All data in a Python program is expressed by the relationship between objects or objects. [Ref: Data Model]
Hong Kong and Taiwan translate objects into "objects" and can regard them as a box containing data, except for pure data, there are other useful property information. In Python, all objects have three attributes: id, type, and value:
+---------------+| || Python Object || |+------+--------+| ID | |+---------------+| Type | |+---------------+| Value| |+---------------+
Id indicates the memory address, which can be viewed through the built-in function id (). type indicates the class of the object. Different classes mean the attributes and methods of the object. You can use type () method View:
def who(obj): print(id(obj), type(obj)) who(1) who(None) who(who) 4515088368 4514812344 4542646064
Objects can be created, named, or deleted as the basic unit in Python. In Python, objects do not need to be deleted manually. The garbage collection mechanism automatically processes objects that are no longer in use. If necessary, you can also use the del statement to delete a variable; the so-called naming refers to attaching a name label to an object for ease of use, that is, declaring or assigning a variable. Next we will focus on how to create an object. Some Python built-in objects can usually be generated using specific syntax. For example, numbers use Arabic numerals directly, strings use quotation marks '', and lists use []. dictionary use {}, function use def syntax, etc. These object types are built in Python. Can we create other types of objects?
Class and instance
Since Python is an object-oriented programming language, users can create their own objects. Generally, class statements are used. Unlike other objects, class-defined objects (called classes) it can be used to generate a new object (called an instance ):
class A: pass a = A() who(A) who(a) 140477703944616 4542635424
In the above example, A is A new class we have created. By calling A (), we can obtain an instance object of type a. We assign it to, that is to say, we have successfully created an object a that is different from all built-in object types. Its type is _ main __. a! So far, we can divide all objects in Python into two types:
Classes that can be used to generate new objects, including built-in int, str, and self-defined;
Instance objects generated by the class, including numbers and strings of the built-in type, and A of the _ main _. a defined type.
There is no problem to simply understand these two objects in terms of concept, but here we will discuss some details that have to be considered in practice:
Some convenient mechanisms are required to implement inheritance, overloading, and other features in object-oriented programming;
Some fixed procedures are required so that we can execute some specific operations in the process of generating instantiated objects;
These two questions are mainly about some special operations of the class, that is, the main content after this article. If you review the two sentences mentioned at the beginning, you may think about how to generate classes since they are also objects? This is what will be discussed in the next article: The class used to generate class objects, that is, Metaclass ).
Super, mro ()
In the last article mentioned in the 0x00 Python Zen, namespace is a wonderful concept. classes or objects play a part of the role of namespaces in Python. For example, some specific methods or attributes are available only for objects of specific types. Although the attributes and methods of different types of objects may have the same name, they belong to different namespaces, the values may be completely different. The namespace issue also needs to be considered when implementing features such as class inheritance and overloading. Taking the implementation of enumeration types as an example, we need to ensure that the attribute names of enumeration objects cannot be repeated, therefore, we need to inherit the built-in dict class:
class _EnumDict(dict): def __init__(self): dict.__init__(self) self._member_names = [] def keys(self): keys = dict.keys(self) return list(filter(lambda k: k.isupper(), keys)) ed = _EnumDict() ed['RED'] = 1 ed['red'] = 2 print(ed, ed.keys()) {'RED': 1, 'red': 2} ['RED']
In the above example, the _ EnumDict overload calls some methods of the parent class dict at the same time. The above syntax is correct, but if we want to change the parent class of _ EnumDict, instead of inheriting from dict, you must manually modify dict in all methods. method (self), which is not a good practice. To solve this problem, Python provides a built-in function super ():
print(super.__doc__) super() -> same as super(__class__, ) super(type) -> unbound super object super(type, obj) -> bound super object; requires isinstance(obj, type) super(type, type2) -> bound super object; requires issubclass(type2, type) Typical use to call a cooperative superclass method: class C(B): def meth(self, arg): super().meth(arg) This works for class methods too: class C(B): @classmethod def cmeth(cls, arg): super().cmeth(arg)
I initially used super () as a pointer to a parent class object, but in fact it can provide more features: given an object and its subclass (here the object must be at least a class object, the subclass can be an Instance Object), and the corresponding method is searched from the namespace of the parent class of the object.
The following code is used as an example:
class A(object): def method(self): who(self) print("A.method") class B(A): def method(self): who(self) print("B.method") class C(B): def method(self): who(self) print("C.method") class D(C): def __init__(self): super().method() super(__class__, self).method() super(C, self).method() # calling C's parent's method super(B, self).method() # calling B's parent's method super(B, C()).method() # calling B's parent's method with instance of C d = D() print("\nInstance of D:") who(d) 4542787992 C.method 4542787992 C.method 4542787992 B.method 4542787992 A.method 4542788048 A.method Instance of D: 4542787992
Of course, we can also use the super () method externally, but we cannot use the default parameter format, because there are no _ class _ and self in the external namespace:
super(D, d).method() # calling D's parent's method with instance d 4542787992 C.method
The above example can be used to describe:
+----------+| A |+----------+| method() <---------------+ super(B,self)+----------+ | |+----------+ +----------+| B | | D |+----------+ super(C,self) +----------+| method() <---------------+ method() |+----------+ +----------+ |+----------+ || C | |+----------+ | super(D,self)| method() <---------------++----------+
We can think that the super () method finds the starting point of Variable Search by tracing to the parent class. But how is the Backtracking order determined? In the above example, the inheritance relationship is the sequence of object-> A-> B-> C-> D. What if it is A complicated inheritance relationship?
class A(object): pass class B(A): def method(self): print("B's method") class C(A): def method(self): print("C's method") class D(B, C): def __init__(self): super().method() class E(C, B): def __init__(self): super().method() d = D() e = E() B's method C's method
In Python, a class Method mro () can be used to specify the search Order. mro is short for Method Resolution Order. It is a class Method instead of an instance Method () the method changes the method parsing sequence in the inheritance, but this needs to be completed in the Meta class. Here we only look at the result:
D. mro () [_ main __. d, _ main __. b, _ main __. c, _ main __. a, object] E. mro () [_ main __. e, _ main __. c, _ main __. b, _ main __. the A, object] super () method is to search for the starting point in the order given by mro (): super (D, d ). method () super (E, e ). method () B's method C's method super (C, e ). method () super (B, d ). method () B's method C's method