基本多态性

多态性是对对象执行操作的能力,无论其类型如何。这通常通过创建基类并具有两个或更多子类来实现,这些子类都实现具有相同签名的方法。操作这些对象的任何其他函数或方法都可以调用相同的方法,而不管它在哪种类型的对象上操作,而无需先进行类型检查。在面向对象的术语中,当类 X 扩展类 Y 时,则 Y 称为超类或基类,X 称为子类或派生类。

class Shape:
    """
    This is a parent class that is intended to be inherited by other classes
    """

    def calculate_area(self):
        """
        This method is intended to be overridden in subclasses.
        If a subclass doesn't implement it but it is called, NotImplemented will be raised.

        """
        raise NotImplemented

class Square(Shape):
    """
    This is a subclass of the Shape class, and represents a square
    """
    side_length = 2     # in this example, the sides are 2 units long

    def calculate_area(self):
        """
        This method overrides Shape.calculate_area(). When an object of type
        Square has its calculate_area() method called, this is the method that
        will be called, rather than the parent class' version.

        It performs the calculation necessary for this shape, a square, and
        returns the result.
        """
        return self.side_length * 2

class Triangle(Shape):
    """
    This is also a subclass of the Shape class, and it represents a triangle
    """
    base_length = 4
    height = 3

    def calculate_area(self):
        """
        This method also overrides Shape.calculate_area() and performs the area
        calculation for a triangle, returning the result.
        """

        return 0.5 * self.base_length * self.height

def get_area(input_obj):
    """
    This function accepts an input object, and will call that object's
    calculate_area() method. Note that the object type is not specified. It
    could be a Square, Triangle, or Shape object.
    """

    print(input_obj.calculate_area())

# Create one object of each class
shape_obj = Shape()
square_obj = Square()
triangle_obj = Triangle()

# Now pass each object, one at a time, to the get_area() function and see the
# result.
get_area(shape_obj)
get_area(square_obj)
get_area(triangle_obj)

我们应该看到这个输出:


4
6.0

没有多态性会发生什么?
如果没有多态性,则在对对象执行操作之前可能需要进行类型检查,以确定要调用的正确方法。以下计数器示例执行与前一代码相同的任务,但不使用多态,get_area() 函数必须执行更多工作。

class Square:

    side_length = 2

    def calculate_square_area(self):
        return self.side_length ** 2

class Triangle:

    base_length = 4
    height = 3

    def calculate_triangle_area(self):
        return (0.5 * self.base_length) * self.height

def get_area(input_obj):

    # Notice the type checks that are now necessary here. These type checks
    # could get very complicated for a more complex example, resulting in
    # duplicate and difficult to maintain code.

    if type(input_obj).__name__ == "Square":
        area = input_obj.calculate_square_area()

    elif type(input_obj).__name__ == "Triangle":
        area = input_obj.calculate_triangle_area()

    print(area)

# Create one object of each class
square_obj = Square()
triangle_obj = Triangle()

# Now pass each object, one at a time, to the get_area() function and see the
# result.
get_area(square_obj)
get_area(triangle_obj)

我们应该看到这个输出:

4
6.0

重要说明请
注意,计数器示例中使用的类是新样式类,如果使用 Python 3,则隐式继承自对象类。多态性在 Python 2.x 和 3.x 中都有效,但是如果在 Python 2.x 解释器中运行,则多态性反例示例将引发异常,因为 type(input_obj)名称将返回,而不是类名实例,如果他们不明确地从 object 继承,导致从未被分配到区域。