Object Oriented Python 简明教程

Inheritance and Polymorphism

继承和多态性——这是 Python 中一个非常重要的概念。如果你想学习,你必须更深入地了解它。

Inheritance and polymorphism – this is a very important concept in Python. You must understand it better if you want to learn.

Inheritance

面向对象编程的主要优势之一是重用。继承就是实现这一目标的机制之一。继承允许程序员首先创建一个通用类或基类,然后稍后将其扩展为更专门的类。它允许程序员编写更好的代码。

One of the major advantages of Object Oriented Programming is re-use. Inheritance is one of the mechanisms to achieve the same. Inheritance allows programmer to create a general or a base class first and then later extend it to more specialized class. It allows programmer to write better code.

使用继承,你可以使用或继承基类中所有可用的数据字段和方法。稍后,你可以添加自己方法和数据字段,因此继承提供了一种组织代码的方法,而不是从头开始重写它。

Using inheritance you can use or inherit all the data fields and methods available in your base class. Later you can add you own methods and data fields, thus inheritance provides a way to organize code, rather than rewriting it from scratch.

在面向对象术语中,当类 X 扩展类 Y 时,Y 被称为超类/父类/基类,X 被称为子类/子类/派生类。这里需要注意的一点是只有非私有的数据字段和方法可供子类访问。私有数据字段和方法仅可在类内访问。

In object-oriented terminology when class X extend class Y, then Y is called super/parent/base class and X is called subclass/child/derived class. One point to note here is that only data fields and method which are not private are accessible by child classes. Private data fields and methods are accessible only inside the class.

创建派生类的语法为 -

syntax to create a derived class is −

class BaseClass:
   Body of base class
class DerivedClass(BaseClass):
   Body of derived class

Inheriting Attributes

现在,看下面的示例 -

Now look at the below example −

inheriting attributes

Output

inheriting attributes output

我们首先创建一个名为 Date 的类,并传递对象作为参数,这里的对象是由 Python 提供的内置类。稍后,我们创建另一个名为 time 的类,并调用 Date 类作为参数。通过此调用,我们可以访问时间类中日期类的所有数据和属性。正因为如此,当我们尝试从我们之前创建的时间类对象 tm 中获取 get_date 方法时,这是可能的。

We first created a class called Date and pass the object as an argument, here-object is built-in class provided by Python. Later we created another class called time and called the Date class as an argument. Through this call we get access to all the data and attributes of Date class into the Time class. Because of that when we try to get the get_date method from the Time class object tm we created earlier possible.

Object.Attribute Lookup Hierarchy

  1. The instance

  2. The class

  3. Any class from which this class inherits

Inheritance Examples

让我们仔细看看继承示例——

Let’s take a closure look into the inheritance example −

inheritance example

让我们创建两个类来参与示例 -

Let’s create couple of classes to participate in examples −

  1. Animal − Class simulate an animal

  2. Cat − Subclass of Animal

  3. Dog − Subclass of Animal

在 Python 中,用于创建对象(实例)并为属性分配值的是类的构造函数。

In Python, constructor of class used to create an object (instance), and assign the value for the attributes.

子类构造函数总是调用父类构造函数以初始化其属性值,然后开始为其属性分配值。

Constructor of subclasses always called to a constructor of parent class to initialize value for the attributes in the parent class, then it start assign value for its attributes.

python constructor

Output

python constructor output

在上面的示例中,我们看到在父类中放置的命令属性或方法,以便所有子类或子类都将从父类继承该属性。

In the above example, we see the command attributes or methods we put in the parent class so that all subclasses or child classes will inherits that property from the parent class.

如果子类尝试从另一个子类继承方法或数据,那么它将引发错误,就像我们看到 Dog 类试图从该 cat 类中调用 swatstring() 方法时,它会引发错误(在本例中类似 AttributeError)。

If a subclass try to inherits methods or data from another subclass then it will through an error as we see when Dog class try to call swatstring() methods from that cat class, it throws an error(like AttributeError in our case).

Polymorphism (“MANY SHAPES”)

多态性是 Python 中类定义的一项重要功能,在您跨类或子类拥有同名方法时使用。这允许函数在不同时间使用不同类型的实体。所以,它提供了灵活性并松散耦合,以便随着时间的推移可以扩展和容易维护代码。

Polymorphism is an important feature of class definition in Python that is utilized when you have commonly named methods across classes or subclasses. This permits functions to use entities of different types at different times. So, it provides flexibility and loose coupling so that code can be extended and easily maintained over time.

这允许函数使用任何这些多态类的对象,而无需了解跨类的区别。

This allows functions to use objects of any of these polymorphic classes without needing to be aware of distinctions across the classes.

多态性可以通过继承来实现,其中子类使用基类方法或重写它们。

Polymorphism can be carried out through inheritance, with subclasses making use of base class methods or overriding them.

让我们用我们之前关于继承的示例来理解多态性的概念,并在两个子类中添加一个称为 show_affection 的通用方法 −

Let understand the concept of polymorphism with our previous inheritance example and add one common method called show_affection in both subclasses −

从示例中我们可以看到,它指的是一种设计,其中不同类型对象可以以相同的方式被对待,或者更具体地说,两个或多个具有同名方法或通用接口的类,因为相同的方法(在本例中为 show_affection)被使用任一类型的对象调用。

From the example we can see, it refers to a design in which object of dissimilar type can be treated in the same manner or more specifically two or more classes with method of the same name or common interface because same method(show_affection in below example) is called with either type of objects.

polymorphism

Output

polymorphism output

因此,所有动物都会表现出感情(show_affection),但它们表现方式不同。“show_affection” 行为因此是多态的,因为它的行为因动物而异。因此,抽象的“动物”概念实际上不会“show_affection”,但特定的动物(例如狗和猫)具有动作“show_affection” 的具体实现。

So, all animals show affections (show_affection), but they do differently. The “show_affection” behaviors is thus polymorphic in the sense that it acted differently depending on the animal. So, the abstract “animal” concept does not actually “show_affection”, but specific animals(like dogs and cats) have a concrete implementation of the action “show_affection”.

Python 本身具有多态的类。例如,len() 函数可以与多个对象一起使用,并且所有函数都根据输入参数返回正确的输出。

Python itself have classes that are polymorphic. Example, the len() function can be used with multiple objects and all return the correct output based on the input parameter.

polymorphic

Overriding

在 Python 中,当一个子类包含一个覆盖超类方法的方法时,还可以通过调用来调用超类方法

In Python, when a subclass contains a method that overrides a method of the superclass, you can also call the superclass method by calling

Super(Subclass, self).method 而不是 self.method。

Super(Subclass, self).method instead of self.method.

Example

class Thought(object):
   def __init__(self):
      pass
   def message(self):
      print("Thought, always come and go")

class Advice(Thought):
   def __init__(self):
      super(Advice, self).__init__()
   def message(self):
      print('Warning: Risk is always involved when you are dealing with market!')

Inheriting the Constructor

如果从我们之前的继承示例中可以看到, init 位于父类中的向上,因为子类 dog 或 cat 没有 init 方法。Python 使用继承属性查找来在 animal 类中查找 init 。当我们创建子类时,它将首先在 dog 类中查找 init 方法,然后在未找到后查看父类 Animal 并找到它们并进行调用。因此,随着我们类设计的变得复杂,我们可能希望首先通过父类构造函数,然后通过子类构造函数来初始化一个实例。

If we see from our previous inheritance example, init was located in the parent class in the up ‘cause the child class dog or cat didn’t‘ve init method in it. Python used the inheritance attribute lookup to find init in animal class. When we created the child class, first it will look the init method in the dog class, then it didn’t find it then looked into parent class Animal and found there and called that there. So as our class design became complex we may wish to initialize a instance firstly processing it through parent class constructor and then through child class constructor.

constructor

Output

constructor output

在上例中——所有动物都有一个名称,所有狗都有一个特定的品种。我们使用 super 来调用父类构造函数。因此,dog 有它自己的 init ,但首先发生的是我们调用 super。Super 是内置函数,它旨在将一个类与其超类或其父类相关联。

In above example- all animals have a name and all dogs a particular breed. We called parent class constructor with super. So dog has its own init but the first thing that happen is we call super. Super is built in function and it is designed to relate a class to its super class or its parent class.

在这种情况下,我们所说的是获取 dog 的超类并将 dog 实例传递给我们在构造函数中所说的任何方法 init 。因此,换句话说,我们使用 dog 对象调用父类 Animal init 。你可能想知道,为什么我们不直接使用 dog 实例来说 Animal init ,我们也可以这样做,但是如果 animal 类名称在将来某个时间发生更改怎么办。如果我们想要重新排列类层次结构,那么 dog 会从另一个类继承。在这种情况下使用 super 会让事情保持模块化,并且易于更改和维护。

In this case we saying that get the super class of dog and pass the dog instance to whatever method we say here the constructor init. So in another words we are calling parent class Animal init with the dog object. You may ask why we won’t just say Animal init with the dog instance, we could do this but if the name of animal class were to change, sometime in the future. What if we wanna rearrange the class hierarchy,so the dog inherited from another class. Using super in this case allows us to keep things modular and easy to change and maintain.

因此,在这个示例中,我们能够将通用 init 功能与更具体的功能相结合。这给了我们机会将通用功能与特定功能分开,这可以消除代码重复,并且以反映系统整体设计的方式将类相互关联。

So in this example we are able to combine general init functionality with more specific functionality. This gives us opportunity to separate common functionality from the specific functionality which can eliminate code duplication and relate class to one another in a way that reflects the system overall design.

Conclusion

  1. init is like any other method; it can be inherited

  2. If a class does not have a init constructor, Python will check its parent class to see if it can find one.

  3. As soon as it finds one, Python calls it and stops looking

  4. We can use the super () function to call methods in the parent class.

  5. We may want to initialize in the parent as well as our own class.

Multiple Inheritance and the Lookup Tree

顾名思义,多重继承是 Python 中的一个类从多个类继承的情况。

As its name indicates, multiple inheritance is Python is when a class inherits from multiple classes.

例如,一个孩子从父母(母亲和父亲)双方继承性格特征。

For example, a child inherits personality traits from both parents (Mother and Father).

Python Multiple Inheritance Syntax

要让一个类从多个父类继承,我们在定义它时将这些类的名称写在派生类的圆括号中。我们用逗号分隔这些名称。

To make a class inherits from multiple parents classes, we write the the names of these classes inside the parentheses to the derived class while defining it. We separate these names with comma.

下面是一个示例:

Below is an example of that −

>>> class Mother:
   pass

>>> class Father:
   pass

>>> class Child(Mother, Father):
   pass

>>> issubclass(Child, Mother) and issubclass(Child, Father)
True

多重继承是指从两个或两个以上的类中继承的能力。当孩子从父母继承,而父母从祖父母类继承时,复杂性就会出现。Python 会爬一个继承树,寻找要从某个对象读取的属性。它将在实例中、类内、父类中和最后从祖父母类中进行检查。现在出现的一个问题是,以什么顺序搜索这些类——广度优先还是深度优先。默认情况下,Python 使用深度优先。

Multiple inheritance refers to the ability of inheriting from two or more than two class. The complexity arises as child inherits from parent and parents inherits from the grandparent class. Python climbs an inheriting tree looking for attributes that is being requested to be read from an object. It will check the in the instance, within class then parent class and lastly from the grandparent class. Now the question arises in what order the classes will be searched - breath-first or depth-first. By default, Python goes with the depth-first.

这就是为什么在下面的图表中,Python 首先在类 A 中搜索 dothis() 方法。因此,以下示例中的方法解析顺序为:

That’s is why in the below diagram the Python searches the dothis() method first in class A. So the method resolution order in the below example will be

Mro- D→B→A→C

Mro- D→B→A→C

查看下面的多重继承图表:

Look at the below multiple inheritance diagram −

multiple inheritance

让我们通过一个示例来了解 Python 的“mro”特性的。

Let’s go through an example to understand the “mro” feature of an Python.

Output

python mro feature output

Example 3

让我们再举一个“菱形”多重继承的示例。

Let’s take another example of “diamond shape” multiple inheritance.

diamond shape multiple inheritance

上面的图表将被认为是模棱两可的。从我们之前的示例中理解“方法解析顺序” .i.e. mro 将为 D→B→A→C→A,但事实并非如此。从 C 中获得第二个 A 时,Python 将忽略前面的 A。因此,在这种情况下,mro 将为 D→B→C→A。

Above diagram will be considered ambiguous. From our previous example understanding “method resolution order” .i.e. mro will be D→B→A→C→A but it’s not. On getting the second A from the C, Python will ignore the previous A. so the mro will be in this case will be D→B→C→A.

让我们基于上面的图表创建一个示例:

Let’s create an example based on above diagram −

method resolution order

Output

method resolution order output

理解以上输出的简单规则是——如果同一个类出现在方法解析顺序中,则这个类的早期出现将从方法解析顺序中移除。

Simple rule to understand the above output is- if the same class appear in the method resolution order, the earlier appearances of this class will be remove from the method resolution order.

总结:

In conclusion −

  1. Any class can inherit from multiple classes

  2. Python normally uses a “depth-first” order when searching inheriting classes.

  3. But when two classes inherit from the same class, Python eliminates the first appearances of that class from the mro.

Decorators, Static and Class Methods

函数(或方法)通过 def 语句创建。

Functions(or methods) are created by def statement.

尽管方法在以下一点上的工作方式与函数完全相同,但方法的第一个参数是实例对象。

Though methods works in exactly the same way as a function except one point where method first argument is instance object.

我们可以根据其行为方式对方法进行分类,例如:

We can classify methods based on how they behave, like

  1. Simple method − defined outside of a class. This function can access class attributes by feeding instance argument:

def outside_func(():
  1. Instance method

def func(self,)
  1. Class method − if we need to use class attributes

   @classmethod
def cfunc(cls,)
  1. Static method − do not have any info about the class

      @staticmethod
def sfoo()

到目前为止,我们已经看到了实例方法,现在是时候深入了解其他两种方法了,

Till now we have seen the instance method, now is the time to get some insight into the other two methods,

Class Method

@classmethod 装饰器是一个内置函数装饰器,它将作为第一个参数传递调用它的类,或调用它的实例的类。该评估的结果会隐藏您的函数定义。

The @classmethod decorator, is a builtin function decorator that gets passed the class it was called on or the class of the instance it was called on as first argument. The result of that evaluation shadows your function definition.

syntax

class C(object):
   @classmethod
   def fun(cls, arg1, arg2, ...):
      ....
fun: function that needs to be converted into a class method
returns: a class method for function

他们有权访问此 cls 参数,它不能修改对象实例状态。这需要访问 self。

They have the access to this cls argument, it can’t modify object instance state. That would require access to self.

  1. It is bound to the class and not the object of the class.

  2. Class methods can still modify class state that applies across all instances of the class.

Static Method

静态方法不接受 self 或 cls(class) 参数,但它可以自由地接受任意数量的其他参数。

A static method takes neither a self nor a cls(class) parameter but it’s free to accept an arbitrary number of other parameters.

syntax

syntax

class C(object):
   @staticmethod
   def fun(arg1, arg2, ...):
   ...
returns: a static method for function funself.
  1. A static method can neither modify object state nor class state.

  2. They are restricted in what data they can access.

When to use what

  1. We generally use class method to create factory methods. Factory methods return class object (similar to a constructor) for different use cases.

  2. We generally use static methods to create utility functions.