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.
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 fromobject
classes (the first letter is lowercase, which is special), soA
the definition of can be written in the following form :class A(object): pass
It's just usually
object
omitted.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
name
attributes: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
name
it 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
__name
changed 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.
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@property
The 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.
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
_name
the first single underscore, which means: although it can be accessed, please treat it as a private attribute and do not access it casually.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
Animal
all objects of its subclasses. As long as therun()
method of the class is written correctly, Python can correctly call therun()
method of the corresponding class during interpretation, that is, the caller only needs to call theanimal_run()
functionrun()
, 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 isrun()
implemented correctly, itanimal_run()
is correct. This is famous“开闭原则”
: open for extension, closed for modification.static language and dynamic language
Take the function above
animal_run()
as an example. For static languages like Java, the arguments passed in must beAnimal
and their subclasses, otherwise therun()
method cannot be called. For a dynamic language like Python, the incoming object is not necessarily required to beAnimal
its subclass, as long as the object has arun()
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 aread()
method for returning the content of the file. But for other objects, as long as theread()
methods are implemented correctly, even if it is not a file object, it can be treated as a file.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
Animal
classes 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:
we can alsoAnimal
inherit from two classes first,Runnable
andFlyable
then 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
Bat
class will have all the propertiesMammalia
andFlyable
methods of the two parent classes. Generally in Java,able
the end class is considered as an interface.When designing the inheritance of classes, the main line is generally single inheritance, such as
Animal
derived from in the above exampleManmalia
, but if some additional functions are to be mixed in subsequent classes, but this function is not unique to this subclass , such as the aboveFlyable
, then you can use multiple inheritance, fromManmalia
andRunnable
derivedBat
classes, that isMinIn设计
, Java uses interfaces to achieve this design.In order to better see the inheritance relationship, the name of the
Runnable
andFlyable
class is generally changed toRunnableMixIn
andFlyableMixIn
, and at the same time, carnivoresCarnivorousMixIn
and herbivores can also be definedHerbivoresMixIn
, so that subclasses have several at the same timeMinIn
: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!