In this article, we will discuss some of the concepts and implementation principles behind classes and objects in Python. We will try to explain the storage of Python class and object attributes, functions and methods, descriptors, optimized support for object memory usage, inheritance and attribute lookup. Let's start with a simple example: Class Employee: Def __init__(self, department, name) cannot be changed when changing class attributes at the instance level: Self. department = department self.name = name @property def inservice(self): self.department = department self.name = name @property def inservice(self): return self.department is not None def __repr__(self): return f"<Employee: {self.department}-{self.name}>" Employee = Employee(' Houzhen03 ') The employee object is an instance of the Employee class, It has two properties, department and name, which belong to the instantiated object. Outsource is a class property, the owner is the class, and all instances of that class share this property value, just like in other object-oriented languages. Changing a class variable affects all instance objects of the class:  >>> e1 = Employee('IT', 'bobo') >>> e2 = Employee('HR', 'cici') >>> e1.outsource, E2. outsource # The outsource attribute of this class is False (False, False) >>> Employee. Outsource = True Also changed >>> E1.outsource, e2.outsource >>> (True, True) This is limited to changing from class, when we change a class variable from an instance: >>> e1 = Employee(' houzhen03', 'Zhangwei06 ') >>> e2 = Employee(' houzhen03',' Zhangwei06 ') >>> e1. E2. outsource (False, False) >>> e1.outsource = True Outsource, e2.outsource (True, False) Yes, when you try to modify a class property at the instance object level, Python does not change the class property value. Instead, it creates an instance property with the same name. This is very true and very safe. When accessing properties, instance properties take precedence over class properties, that is, to find out if the instance has the property first, and if not, to find class properties as explained in the inheritance and attribute Lookup section. In particular, when class attributes are of mutable type, you can change them at the instance object level: Def __init__(self,provence=None,city=None,name=None): self.provence = provence self.city = city self.name = name def eat(self): Print (houzhen. Temp_list) houzhen. Temp_list. Append (444) # print(houzhen Modify mutable class attributes at the instance object level, Print (houzhen. Temp_list) sun = houzhen (" 广 州 "," 广 州 "," 广 州 ") print(sun. Temp_list) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # < 1 > instance attributes: In Python, all instance attributes are stored in the __dict__ dictionary, a regular dict from which instance attributes are retrieved and modified, and which is completely open to developers. > > > e = the Employee (' IT ', 'bobo) # initialize an instance object > > > e. __dict__ {' department' : 'IT', 'name' : 'bobo'} >>> type(e.__dict__) dict >>> e.name is e.__dict__['name'] True >>> e.__dict__['department'] = 'HR' >>> Since instance attributes are stored in dictionaries, we can easily add or remove fields to objects at any time: > > > e.a ge = 30 # does not define the age attribute > > > e.a ge 30 > > > e. __dict__ {' department ':' IT ', 'name' : "bobo", "age" : 30} >>> del e.age >>> e.__dict__ {'department': 'IT', 'name': Similarly, class attributes are stored in the class's __dict__ dictionary: Unlike the "open" instance dictionary, the dictionary used by class attributes is an MappingProxyType object, which is a setattr-free dictionary. This means that it is read-only to the developer, precisely to ensure that the keys of class attributes are strings to simplify and speed up the lookup of new class attributes and __mro__ search logic. >>> Employee.__dict__ mappingproxy({'__module__': '__main__', 'outsource': True, '__init__': <function __main__.Employee.__init__(self, department, name)>, 'inservice': <property at 0x108419ea0>, '__repr__': <function __main__.Employee.__repr__(self)>, '__str__': <function __main__.Employee.__str__(self)>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__doc__': None} >>> Type (employee.__dict__) mappingProxy <3> A general rule for inheritance and attribute lookup: So far, we've seen that all attributes and methods are stored in two __dict__ dictionaries. Now let's look at how Python does attribute lookup. In Python 3, all classes implicitly inherit from Object, so there is always an inheritance relationship, and Python supports multiple inheritance: >>> Class A:... pass ... >>> class B: ... pass ... >>> class C(B): ... pass ... >>> Class D(A, C): pass ... >>> D.mro() [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.B'>, <class 'object'>] <4> Functions and Methods We know that methods are class-specific functions. The only difference (if any) is that the first argument to a method is often reserved for a class or instance object. In Python, We agreed on CLS or self, but you could call it anything like this(just don't do that). As we saw in the previous section, functions implement objects of the __get__() method, so they are non-data descriptors. It is in Python's access (call) method support that the called function is bound to a method by calling __get__().Copy the code