python面向对象之——继承
继承是面向对象编程中的一个重要概念。通过继承,一个对象可以基于另一个已存在的对象来创建,从而从已有的对象中获取属性和方法。被继承的对象称为父类(或基类、超类),继承自父类的对象称为子类(或派生类)。子类可以继承父类的属性和方法,并且可以添加自己的属性和方法。
通过继承,可以实现代码的复用,减少重复编写相同代码的工作。子类可以重写父类的方法,对其进行扩展或修改,从而实现多态性。
继承的一个主要目的是实现分类和封装,通过将共同的属性和方法抽象到父类中,可以更好地组织和管理代码。
一般来说,继承的关系是单向的,子类继承了父类的特性,但父类不知道子类的存在。但子类可以通过调用父类的方法来获取父类的特性。
Python中的继承代码格式如下:
class ParentClass:
# 父类属性和方法
class ChildClass(ParentClass):
# 子类属性和方法
父类和子类分别定义在类之间的括号中,用于指定父类。子类继承了父类的属性和方法。在子类中可以新增或覆盖父类的属性和方法。
例如,下面是一个使用继承的示例代码:
class Shape:
def __init__(self, name):
self.name = name
def area(self):
pass
class Rectangle(Shape):
def __init__(self, name, width, height):
super().__init__(name)
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, name, radius):
super().__init__(name)
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
rect = Rectangle("长方形", 5, 10)
print(rect.area()) # 输出:50
circle = Circle("圆形", 2)
print(circle.area()) # 输出:12.56
在这个示例中,Shape
是父类,Rectangle
和Circle
是子类。子类通过继承父类的属性和方法,并且可以覆盖父类的方法来实现具体的功能。
创建子类对象时是否会使用父类对象的new和init方法
在Python中,当你创建一个子类的对象时,Python会首先调用子类的__new__
方法来创建一个新的实例。如果子类没有定义自己的__new__
方法,那么它会调用其直接父类的__new__
方法,这个过程会一直递归到基类(通常是object
)为止。
接着,一旦新实例被创建,就会调用子类的__init__
方法来初始化这个实例。如果子类没有定义自己的__init__
方法,那么它的直接父类的__init__
方法会被调用,这个过程同样会递归到基类。
然而,对于__init__
方法,Python不会自动调用父类的构造器,除非子类显式地这样做。子类必须显式地调用父类的__init__
方法,通常通过super()
函数来实现。例如:
class Parent:
def __init__(self):
print("Parent's init called")
class Child(Parent):
def __init__(self):
super().__init__() # 显式调用父类的init
print("Child's init called")
在这个例子中,当你创建Child
类的实例时,Parent
类的__init__
方法也会被调用,因为Child
类中的__init__
方法显式地调用了super().__init__()
。
如果你省略了super().__init__()
调用,那么Parent
类的__init__
方法将不会被调用,这可能会导致一些问题,比如父类的初始化代码没有执行,或者父类期望的一些属性没有被正确设置。
当一个子类同时重写了__new__
和__init__
方法时,创建对象的过程如下:
首先,Python会调用子类的
__new__
方法来创建一个实例。如果子类没有定义__new__
方法,则会调用父类的__new__
方法。这个过程会一直继续到object
基类为止。__new__
方法应该返回一个新创建的实例。在__new__
中,你可以进行一些额外的处理,如改变返回的实例类型或根据某些条件改变实例的行为。接着,在
__new__
返回的实例上,Python会调用__init__
方法。如果子类定义了自己的__init__
方法,那么它会被调用;如果没有,就会调用父类的__init__
方法,以此类推,直到到达object
类。与
__init__
不同,Python不会自动调用父类的__init__
方法。你必须在子类的__init__
方法中显式地调用它,通常使用super()
函数。
例如:
class Base:
def __new__(cls, *args, **kwargs):
print("Base's __new__ called")
return super().__new__(cls)
def __init__(self):
print("Base's __init__ called")
class Derived(Base):
def __new__(cls, *args, **kwargs):
print("Derived's __new__ called")
return super().__new__(cls)
def __init__(self):
print("Derived's __init__ called")
super().__init__()
# 创建Derived的实例
instance = Derived()
在这个例子中:
- 创建
Derived
实例时,Derived
的__new__
方法首先被调用,然后是Base
的__new__
方法(通过super()
)。 - 之后,
Derived
的__init__
方法被调用,它又显式地调用了Base
的__init__
方法(同样通过super()
)。
因此,正确的调用顺序是:
Derived
的__new__
Base
的__new__
Derived
的__init__
Base
的__init__
注意,__new__
是一个静态方法,而__init__
是一个实例方法。这意味着__new__
可以访问类对象,但不能访问实例(除非它已经被创建),而__init__
则是在实例已经创建后被调用的。