属性是类的特征或数据成员,可以包含各种数据类型,如整数、字符串、列表等。通过属性,我们可以为类定义各种特征和行为。
继承是一种类之间的关系,它允许一个类(称为子类)继承另一个类(称为父类)的属性和方法。通过继承,子类可以重用父类的功能,并且还可以根据需要添加新的属性和方法。
- 属性表示对象的状态或数据,是对象的特征。在面向对象编程中,类可以定义属性,而实例则拥有这些属性的具体值。
- 继承是一种对象间的关系,一个类可以继承另一个类的属性和方法,从而复用已有的代码并扩展功能。
- 继承允许我们建立类的层次结构,从抽象类继承出具体的子类,子类可以拥有父类的所有属性和方法,同时也可以根据需要添加自己特有的属性和方法。
1 属性(Attributes)
在Python中,可以通过在类中定义变量来创建属性。这些变量被称为实例变量或属性。每个实例变量都属于类的一个实例,并且可以根据需要分配不同的值。
1.1 属性的基本语法
定义属性:属性通常在类的内部定义,可以通过在类中声明变量来创建属性。属性可以是实例属性(属于类的实例)或类属性(属于类本身)。
class MyClass: # 定义实例属性 instance_var = 10 def __init__(self): # 初始化实例属性 self.name = "John"
访问属性:在类的方法中可以通过使用self关键字来访问实例属性。对于类属性,可以使用类名来访问。
class MyClass: class_var = 20 def __init__(self): self.instance_var = 10 def get_class_var(self): # 访问类属性 return MyClass.class_var def get_instance_var(self): # 访问实例属性 return self.instance_var
修改属性:类的方法可以通过self关键字修改实例属性的值。
class MyClass: def __init__(self): self.instance_var = 10 def set_instance_var(self, value): # 修改实例属性的值 self.instance_var = value
属性的可见性:在Python中,默认情况下,类的所有属性都是公有的,可以在类的外部访问。如果希望将属性设置为私有的,可以在属性名前添加两个下划线__。
class MyClass: def __init__(self): # 私有属性 self.__private_var = 10 def get_private_var(self): # 访问私有属性 return self.__private_var def set_private_var(self, value): # 修改私有属性的值 self.__private_var = value
属性的装饰器:可以使用@property装饰器将类的方法转换为属性。这样可以在使用属性时像访问属性一样调用方法。
class MyClass: def __init__(self): self.__private_var = 10 @property def private_var(self): # 使用装饰器将方法转换为属性 return self.__private_var
示例:
class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year car1 = Car("Toyota", "Corolla", 2022) car2 = Car("Honda", "Civic", 2021) print(car1.make) # 输出:Toyota print(car2.year) # 输出:2021
在上面的示例中,我们创建了一个名为Car的类,并在初始化方法__init__中定义了三个属性:make、model和year。然后,我们创建了两个Car类的实例,并为每个实例分配了不同的值。
1.2 创建用于计算的属性
在Python中,我们可以使用@property装饰器来创建用于计算的属性。计算属性是一种通过调用特定方法计算得到的属性值,而不是直接存储在实例变量中的值。计算属性可以根据其他实例变量的值来计算,或者进行复杂的计算逻辑。
使用@property装饰器可以创建用于计算属性的语法格式。@property装饰器允许我们将一个方法转换为只读属性,该属性的值是通过计算而来,而不是存储在实例变量中。
以下是@property的语法格式:
class ClassName: def __init__(self, ...): # 初始化实例变量 @property def attribute_name(self): # 计算属性的逻辑 return computed_value
在上面的语法格式中:
- ClassName 是类的名称,表示我们正在定义一个类。
- ... 是__init__方法的参数列表,用于初始化实例变量。
- attribute_name 是计算属性的名称,可以根据实际情况来指定。
- computed_value 是通过计算得到的属性值,可以根据实际情况来计算。
使用@property装饰器可以将一个方法定义为计算属性,并且可以像访问普通属性一样访问它。当访问计算属性时,实际上是调用了被@property装饰的方法,并返回该方法的返回值作为属性值。
在使用@property装饰器时,需要注意以下几点:
计算属性的名称和实例变量的名称应该不同,否则会导致无限递归。
计算属性只能用于读取,不能用于修改。如果想要修改计算属性的值,需要定义一个对应的setter方法,并使用@property.setter装饰器。
下面是一个示例,演示如何创建一个计算属性:
class Circle: def __init__(self, radius): self.radius = radius @property def diameter(self): return self.radius * 2 @property def area(self): return 3.14 * (self.radius ** 2) @property def circumference(self): return 2 * 3.14 * self.radius # 创建Circle对象 circle = Circle(5) # 访问计算属性 print(circle.diameter) # 输出:10 print(circle.area) # 输出:78.5 print(circle.circumference) # 输出:31.400000000000002 # 修改radius属性并重新计算计算属性 circle.radius = 8 print(circle.diameter) # 输出:16 print(circle.area) # 输出:201.12 print(circle.circumference) # 输出:50.24
在上面的示例中,我们创建了一个名为Circle的类,其中包含radius属性和三个计算属性:diameter、area和circumference。通过@property装饰器,我们将这三个方法定义为计算属性,并通过访问这些计算属性来获取计算得到的结果。
计算属性可以动态地计算属性值,而不需要额外的存储空间,从而节省了内存和代码维护成本。在实际应用中,计算属性常用于根据对象的其他属性来计算相关的值,或者进行复杂的数学计算和逻辑操作。
1.3 属性的安全保护机制
在Python中,可以通过设置访问控制来为属性设置安全机制,以防止意外地修改或访问属性。在Python中,有两种常用的访问控制方式:公开访问和私有访问。
公开访问: 公开访问是Python默认的属性访问方式,即所有属性都可以直接访问和修改。这种方式没有访问控制,属性的访问和修改是完全开放的。例如:
class Circle: def __init__(self, radius): self.radius = radius circle = Circle(5) print(circle.radius) # 输出:5 circle.radius = 8 print(circle.radius) # 输出:8
私有访问: 为了设置安全机制,可以在属性名前加上两个下划线"__",将属性设置为私有属性。私有属性只能在类的内部访问,外部无法直接访问和修改。要访问私有属性,可以通过公开的访问接口进行间接访问。例如:
class Circle: def __init__(self, radius): self.__radius = radius def get_radius(self): return self.__radius def set_radius(self, radius): if radius > 0: self.__radius = radius circle = Circle(5) print(circle.get_radius()) # 输出:5 # 试图直接访问私有属性将报错 # print(circle.__radius) # 报错:'Circle' object has no attribute '__radius' circle.set_radius(8) print(circle.get_radius()) # 输出:8
通过以上示例,我们在属性名前添加了两个下划线"__",将radius属性设置为私有属性。为了访问和修改私有属性,我们定义了公开的访问接口get_radius()和set_radius(),通过这些接口间接地访问和修改私有属性。
通过使用私有属性和公开访问接口,可以在类的内部控制对属性的访问和修改,从而实现属性的安全性。这样可以防止外部不恰当地修改属性,保护了属性的完整性和数据安全。
2 继承(Inheritance)
继承是面向对象编程中的一个重要概念,它允许我们创建一个新的类(称为子类)来继承另一个已有类(称为父类)的属性和方法。子类可以继承父类的所有公有成员,并且还可以添加自己的成员。继承使得代码重用和组织变得更加简单和有效。
2.1 继承的基本语法
class ParentClass: # 父类的属性和方法 class ChildClass(ParentClass): # 子类继承父类的属性和方法,并可以添加自己的属性和方法
在上面的语法中,我们首先定义了一个父类ParentClass,其中包含一些属性和方法。然后我们定义一个子类ChildClass,并在括号中指定父类名ParentClass。子类ChildClass继承了父类ParentClass的所有属性和方法,并且还可以添加自己的属性和方法。
在Python中,可以通过将父类作为参数传递给子类来实现继承。子类将继承父类的属性和方法,并可以在需要时添加新的属性和方法。
以下是一个简单的示例,演示了如何创建一个父类和一个子类,并通过继承获得父类的属性和方法:
# 定义父类 class Animal: def __init__(self, name, species): self.name = name self.species = species def make_sound(self): pass # 定义子类,并继承父类Animal class Dog(Animal): def __init__(self, name, breed): # 调用父类的构造函数 super().__init__(name, species="Dog") self.breed = breed def make_sound(self): return "Woof!" # 创建子类对象 dog = Dog("Buddy", "Labrador") print(dog.name) # 输出:Buddy print(dog.species) # 输出:Dog print(dog.breed) # 输出:Labrador print(dog.make_sound()) # 输出:Woof!
在上面的示例中,我们定义了一个Animal父类,其中包含两个属性name和species,以及一个抽象方法make_sound。然后我们定义了一个Dog子类,并通过继承获得了父类Animal的属性和方法。在子类中,我们还添加了一个自己的属性breed,并实现了make_sound方法。通过继承,我们可以在子类中重用父类的代码,并且还可以扩展和定制子类的功能。
2.2 方法的重写
方法的重写(Method Overriding)是面向对象编程中的一个重要概念,它允许子类覆盖(重写)父类中已有的方法,从而实现对方法的定制和扩展。当子类中定义了一个与父类中同名的方法时,子类的方法将覆盖父类的方法,从而在子类对象中调用该方法时会执行子类中的实现而不是父类的实现。
重写方法的基本语法如下:
class ParentClass: def some_method(self): # 父类的方法实现 class ChildClass(ParentClass): def some_method(self): # 子类重写的方法实现
在上面的语法中,我们定义了一个父类ParentClass,其中包含一个名为some_method的方法。然后我们定义了一个子类ChildClass,并在其中重新定义了some_method方法。当子类对象调用some_method方法时,将会执行子类的方法实现。
以下是一个示例,演示了如何在子类中重写父类的方法:
# 定义父类 class Animal: def make_sound(self): return "Some generic sound" # 定义子类,并继承父类Animal class Dog(Animal): def make_sound(self): return "Woof!" # 创建子类对象 dog = Dog() print(dog.make_sound()) # 输出:Woof!
在上面的示例中,我们定义了一个父类Animal,其中包含一个make_sound方法,它返回一个通用的声音字符串。然后我们定义了一个Dog子类,并在其中重写了make_sound方法,使其返回"Woof!"。当我们创建子类对象并调用make_sound方法时,将会执行子类Dog中重写的方法,输出"Woof!",而不是父类Animal中的实现。这就是方法重写的作用,它允许子类在需要的时候定制和扩展父类的方法。
2.3 派生类中调用基类的_init_()方法
在派生类(子类)中调用基类(父类)的__init__()方法,可以通过使用super()函数来实现。super()函数是Python内置函数,它用于访问父类的方法和属性。
在派生类的__init__()方法中使用super()函数,可以在子类的构造函数中先调用父类的构造函数,然后再添加子类自己的初始化代码。这样可以确保子类对象在初始化时包含父类的属性。
下面是一个示例,演示了如何在子类中调用基类的__init__()方法:
class ParentClass: def __init__(self, name): self.name = name class ChildClass(ParentClass): def __init__(self, name, age): super().__init__(name) # 调用父类的__init__方法 self.age = age # 创建子类对象 child = ChildClass("Alice", 25) print(child.name) # 输出:Alice print(child.age) # 输出:25
在上面的示例中,我们定义了一个父类ParentClass,其中有一个__init__()方法,用于初始化name属性。
又定义了一个子类ChildClass,并在其__init__()方法中使用super().__init__(name)调用了父类的__init__()方法,从而在子类对象初始化时设置了name属性。
然后我们添加了子类自己的初始化代码,设置了age属性。最后,我们创建了子类对象并访问了name和age属性,验证了调用基类__init__()方法的正确性。
3 总结
属性:
- 属性用于存储数据或计算属性值,是类的成员之一。
- 在类中可以通过在类体中声明变量来定义属性。属性可以是实例属性(属于类的实例)或类属性(属于类本身)。
- 实例属性通过self关键字在类的方法中访问和修改,而类属性可以使用类名来访问。
- 可以使用@property装饰器将方法转换为属性,从而实现属性的计算和访问控制。
- 属性可以设置为私有的,通过在属性名前添加两个下划线__来实现私有属性。
继承:
- 继承是面向对象编程中实现代码重用的机制,允许一个类(派生类)继承另一个类(基类)的属性和方法。
- 派生类可以获得基类的所有属性和方法,并可以在派生类中添加新的属性和方法,或重写基类的方法。
- 继承的关系形成了类的层次结构,子类继承了父类的特性,并可以进一步派生出更多的子类。
- 使用继承可以减少代码的重复,提高代码的可维护性和可扩展性。