Python Learning Path 8.1 - Supplement to Python Classes

This series is a compilation of notes for the introductory book "Python Programming: From Getting Started to Practice", which belongs to the primary content. The title sequence follows the title of the book.

This chapter is mainly a supplement to the previous chapter on Python classes.

  1. Derive all classes from one class

    The previous article said that the definition and inheritance of Python classes are generally in the following form:

    class A:   # 或者写成class A():
       pass
    
    class B(A):
       pass

    In fact, for a class A, it is not a real base class, but similar to Java, all classes in Python ultimately inherit from objectclasses (the first letter is lowercase, which is special), so Athe definition of can be written in the following form :

    class A(object):
       pass

    It's just usually objectomitted.

  2. restriction of visit

    From the previous article, we know that the properties of a class can be accessed directly. If we need to restrict access, we can define corresponding methods. In Python, for general attributes, in the words of C++ or Java, they are public attributes, which can be accessed directly from the outside, such as the following nameattributes:

    class A:
       def __init__(self, name):
           self.name = name

    But if we put two underscores in front of this property, it turns into something like this:

    class A:
       def __init__(self, name):
           self.__name = name

    Then nameit becomes a private property, which can only be accessed inside the object. If you want to access it in the following form, an error will be reported:

    
    # 代码:
    
    class A:
       -- snip --
    
    a = A("test")
    print(a.__name)
    
    
    # 结果:
    
    AttributeError: 'A' object has no attribute '__name'

    Is it really impossible to access this property? Luckily or unfortunately, Python doesn't have so-called true private attributes, all attributes of classes in Python can be accessed. The Python interpreter just __namechanged its name to:

    self._A__name

    That is, a single underscore and the class name are added in front.

    
    # 代码:
    
    class A:
       -- snip --
    
    a = A("test")
    print(a._A__name)
    
    
    # 结果:
    
    test

    Accessing properties in this way is strongly discouraged! Also, different versions of the Python interpreter will change such attributes to different names.

  3. Use decorators

    In the previous point, I talked about accessing the attributes of the class through methods. This method is generally called . Finally, the method of the class is called when it is called. Now we use the built-in decorator in get/set方法Python to access the attributes of the class. Finally, when the call is made, it is @propertyThe property called, in fact, it turns the method of the class into a property through the decorator. get/set方法Here 's a code comparison of accessing properties via decorators and via :

    class Teacher:
       def __init__(self, name):
           self.name = name
    
       def get_name(self):
           return self.name
    
       def set_name(self, name):
           # 可以加上一些限制
           self.name = name
    
    class Student:
       def __init__(self, name):
           self._name = name
    
       @property
       def name(self):
           return self._name
    
       @name.setter
       def name(self, name):
           # 可以加上一些限制
           self._name = name
    
    t = Teacher("Miss")
    s = Student("Boy")
    
    print(t.get_name())
    print(s.name)
    t.set_name("Miss Lee")
    s.name = "Kevin"

    It can also be seen from the above code that when defining, there is not much difference in the amount of code between the two, but when calling, it is obviously more convenient to use the decorator.

  4. Other types of properties in the class

    In addition to the common attributes and the above-mentioned private attributes, there are also attributes with double underscores before and after in the class . For example __xxx__, they are special variables that can be accessed directly, not private attributes, so they are generally not used __name__. __score__Such attribute names, for The same is true for methods, not only __init__()such methods, but also many methods with double underscores before and after, for example __del__(), it is the destructor of a class. Many of these methods will be covered in future articles.

    There are not only double-underlined attributes, but also single-underlined attributes, such as _namethe first single underscore, which means: although it can be accessed, please treat it as a private attribute and do not access it casually.

  5. Complementary to polymorphism

    A subclass can be considered a type of a superclass, but a superclass cannot be considered a type of a subclass. for example:

    
    # 代码:
    
    class Animal:
       pass
    
    class Dog(Animal):
       pass
    
    a = Animal()
    d = Dog()
    
    print(isinstance(d, Animal))
    print(isinstance(a, Dog))
    
    
    # 结果:
    
    True
    False

    That is, if we define a function like this:

    def animal_run(animal):
       animal.run()

    It receives Animalall objects of its subclasses. As long as the run()method of the class is written correctly, Python can correctly call the run()method of the corresponding class during interpretation, that is, the caller only needs to call the animal_run()function run(), regardless of the details of the method of the class, whether it is an existing The class is still a newly extended subclass, as long as it is run()implemented correctly, it animal_run()is correct. This is famous “开闭原则”: open for extension, closed for modification.

  6. static language and dynamic language

    Take the function above animal_run()as an example. For static languages ​​like Java, the arguments passed in must be Animaland their subclasses, otherwise the run()method cannot be called. For a dynamic language like Python, the incoming object is not necessarily required to be Animalits subclass, as long as the object has a run()method. This is dynamic language “鸭子类型”, as long as it "looks like a duck and walks like a duck", it can be regarded as a duck. Python “file-like object”is a kind of "duck type". For real file objects, there is a read()method for returning the content of the file. But for other objects, as long as the read()methods are implemented correctly, even if it is not a file object, it can be treated as a file.

  7. Multiple Inheritance and MixIn Design

    The inheritance in the previous article is single inheritance, but Python, like C++, supports multiple inheritance; Java only supports single inheritance, and she achieves the effect of multiple inheritance through interface classes. First of all, we need to understand why multiple inheritance exists. Still taking Animalclasses as an example, among animals there are mammals, oviparous animals, flying animals and non-flying animals, which are two major classifications. If we want to derive a flying mammal (such as a bat), if we follow single inheritance, we can do the following:
    write picture description here
    we can also Animalinherit from two classes first, Runnableand Flyablethen inherit from mammals and oviparous classes (equivalent to the above The second and third layers of the figure have changed positions), but from this single inheritance, it can be seen that if the number of classifications increases, the number of classes will increase exponentially. Therefore, multiple inheritance is generally used:

    class Animal:
       pass
    
    class Mammalia(Animal):
       pass
    
    class Flyable:
       def fly(self):
           print("Flying...")
    
    class Bat(Mammalia, Flyable):
       pass

    This Batclass will have all the properties Mammaliaand Flyablemethods of the two parent classes. Generally in Java, ablethe end class is considered as an interface.

    When designing the inheritance of classes, the main line is generally single inheritance, such as Animalderived from in the above example Manmalia, but if some additional functions are to be mixed in subsequent classes, but this function is not unique to this subclass , such as the above Flyable, then you can use multiple inheritance, from Manmaliaand Runnablederived Batclasses, that is MinIn设计, Java uses interfaces to achieve this design.

    In order to better see the inheritance relationship, the name of the Runnableand Flyableclass is generally changed to RunnableMixInand FlyableMixIn, and at the same time, carnivores CarnivorousMixInand herbivores can also be defined HerbivoresMixIn, so that subclasses have several at the same time MinIn:

    class Dog(Mammalia, RunnableMixIn, CarnivorousMixIn):
       pass

    So when designing classes, we should give priority to combining multiple inheritance through multiple inheritance MinIn, rather than directly considering more levels of inheritance.

    Finally, most of the content in this article is based on Mr. Liao Xuefeng's blog. Thank you Mr. Liao Xuefeng!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325657951&siteId=291194637