在Python中,类(class)是面向对象编程(OOP)的核心概念之一。类提供了一种将数据和功能组织在一起的方式,使得代码更加模块化、可重用和易于维护。 类操作的相关示例代码如下:
# 基本结构
"""
核心概念:封装、继承、多态。
类的结构:类属性、实例属性、方法(实例方法/类方法/静态方法)。
访问控制:通过命名约定(_ 和 __)实现封装。
特殊方法:重载运算符或定义对象行为(如 __str__)。
高级特性:抽象基类、属性装饰器、组合设计模式。
"""
class Dog:
"""类的文档字符串(描述类的功能)"""
# 定义了一个类属性species,它被所有Dog类的实例共享。
species = "Canis familiaris" # 类属性(所有实例共享)
# __init__方法:这是一个特殊的方法,也称为构造函数。当创建Dog类的实例时,__init__方法会自动被调用。
# self是一个约定俗成的参数名,它代表类的实例本身。
# 在调用__init__方法时,Python 会自动将实例作为第一个参数传递给self。name和age是用户传递的参数,用于初始化实例的属性。
def __init__(self, name, age): # __init__ 是构造函数,用于初始化实例属性。
"""初始化方法(构造函数)"""
self.name = name # 实例属性
self.age = age
# self参数:同样,self参数代表类的实例本身,通过self.name可以访问实例的name属性。
def bark(self): # self 表示实例自身,是实例方法的第一个参数。
"""实例方法"""
print(f"bark:{self.name} says: Woof!")
# 实例化对象
# 创建了一个Dog类的实例my_dog,并将名字"Buddy"和年龄3传递给__init__方法进行初始化。
my_dog = Dog("Buddy", 3)
my_dog.bark() # 输出: Buddy says: Woof!
print(my_dog.species) # 输出: Canis familiaris
# 类定义示例
class EricClass:
# 类属性
class_attribute = "I am a class attribute"
# 初始化方法(构造器)
def __init__(self, instance_attribute):
self.instance_attribute = instance_attribute
# 实例方法
def instance_method(self):
return f"Instance attribute: {self.instance_attribute}"
# 类属性与实例属性
# 类属性:定义在类体中的变量,属于类本身,所有实例共享同一个类属性。
# 实例属性:通过__init__方法或其他实例方法定义的变量,属于类的实例(对象),每个实例有自己的实例属性。
class BarryClass:
class_attribute = "Class Attribute"
def __init__(self, instance_value):
self.instance_attribute = instance_value
# 创建实例
obj1 = BarryClass("Instance 1")
obj2 = BarryClass("Instance 2")
# 访问类属性
print(BarryClass.class_attribute) # 输出: Class Attribute
print(obj1.class_attribute) # 输出: Class Attribute
# 修改类属性
BarryClass.class_attribute = "Modified Class Attribute"
print(obj1.class_attribute) # 输出: Modified Class Attribute
print(obj2.class_attribute) # 输出: Modified Class Attribute
# 访问实例属性
print(obj1.instance_attribute) # 输出: Instance 1
print(obj2.instance_attribute) # 输出: Instance 2
# 方法
# 实例方法:第一个参数是self,代表类的实例本身。
# 类方法:使用@classmethod装饰器,第一个参数是cls,代表类本身。
# 静态方法:使用@staticmethod装饰器,不接收self或cls参数。
class JimClass:
class_attribute = "Class Attribute"
def __init__(self, instance_value):
self.instance_attribute = instance_value
# 实例方法
def instance_method(self):
return f"Instance attribute: {self.instance_attribute}"
# 类方法
@classmethod
def class_method(cls):
return f"Class attribute: {cls.class_attribute}"
# 静态方法
@staticmethod
def static_method():
return "This is a static method"
# 创建实例
obj = JimClass("Instance Value")
# 调用方法
print(obj.instance_method()) # 输出: Instance attribute: Instance Value
print(obj.class_method()) # 输出: Class attribute: Class Attribute
print(JimClass.class_method()) # 输出: Class attribute: Class Attribute
print(obj.static_method()) # 输出: This is a static method
print(JimClass.static_method()) # 输出: This is a static method
# 继承
class ParentClass:
def __init__(self, parent_value):
self.parent_attribute = parent_value
def parent_method(self):
return f"Parent attribute: {self.parent_attribute}"
class ChildClass(ParentClass):
def __init__(self, parent_value, child_value):
super().__init__(parent_value) # 调用父类的构造器
self.child_attribute = child_value
def child_method(self):
return f"Child attribute: {self.child_attribute}"
# 创建子类实例
child_obj = ChildClass("Parent Value", "Child Value")
# 调用父类方法
print(child_obj.parent_method()) # 输出: Parent attribute: Parent Value
# 调用子类方法
print(child_obj.child_method()) # 输出: Child attribute: Child Value
# 继承与多态
class Animal:
def __init__(self, name):
self.name = name
# speak 方法被定义为抛出 NotImplementedError 异常。
# 这是一种抽象方法的实现方式,表明这个方法在基类中没有具体实现,子类必须重写这个方法才能正常使用。
def speak(self):
raise NotImplementedError("子类必须实现此方法")
# class Cat(Animal) 表明 Cat 类继承自 Animal 类。这意味着 Cat 类可以继承 Animal 类的所有属性和方法。
# 子类通过 class SubClass(ParentClass) 语法继承父类。
# Python 支持多重继承(多个父类),需注意方法解析顺序(MRO)。
class Cat(Animal): # 继承自 Animal
# 子类可重写父类方法(如 speak())实现多态。
def speak(self):
print(f"{self.name} says: Meow!")
class Duck(Animal):
def speak(self):
print(f"{self.name} says: Quack!")
# 多态
# 多态:多态是面向对象编程的一个重要特性,它允许不同的对象对同一消息做出不同的响应。
# 在这个例子中,animals 列表包含了 Cat 和 Duck 类的实例。
# 当使用 for 循环遍历这个列表并调用每个对象的 speak 方法时,Python 会根据对象的实际类型调用相应的 speak 方法。
# 这就是多态的体现,相同的方法调用(animal.speak())在不同的对象上产生了不同的行为。
animals = [Cat("Kitty"), Duck("Donald")]
for animal in animals:
animal.speak() # 分别输出 Kitty says: Meow! 和 Donald says: Quack!
# 封装
class EncapsulatedClass:
def __init__(self, value):
self.__private_attribute = value # 私有属性
def get_private_attribute(self):
return self.__private_attribute
def set_private_attribute(self, value):
self.__private_attribute = value
# 创建实例
obj = EncapsulatedClass("Private Value")
# 访问私有属性(通过公共方法)
print(obj.get_private_attribute()) # 输出: Private Value
# 修改私有属性(通过公共方法)
obj.set_private_attribute("New Private Value")
print(obj.get_private_attribute()) # 输出: New Private Value
# 直接访问私有属性(不推荐,会导致AttributeError)
# print(obj.__private_attribute) # AttributeError: 'EncapsulatedClass' object has no attribute '__private_attribute'
# 封装与访问
# 通过双下划线 __var 定义私有属性/方法(实际会被重命名为 _ClassName__var)。
# 单下划线 _var 表示“受保护”成员(约定俗成,非强制)。
# 通过公共方法(如 get_balance())提供安全访问。
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性(双下划线开头)
# 在 Python 中,不支持方法重载,即不能定义多个同名的方法。当你定义了两个 __init__ 方法时,后面的定义会覆盖前面的定义。
# def __init__(self, balance, name):
# self.__balance = balance # 私有属性(双下划线开头)
# self.__name = name
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self): # 公共方法访问私有属性
return self.__balance
account = BankAccount(1000)
# account.__balance # 报错:AttributeError(无法直接访问)
# 通过调用公共方法 get_balance 来访问私有属性 __balance,避免直接访问私有属性导致的 AttributeError 异常。
print(account.get_balance()) # 输出: 1000
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# __add__ 方法:这是 Python 中的特殊方法,用于重载加法运算符 +。
# 当对两个 Vector 实例使用 + 运算符时,Python 会自动调用 __add__ 方法。
def __add__(self, other): # 重载加法运算符
# 该方法将两个向量的对应分量相加,然后创建并返回一个新的 Vector 实例,其 x 和 y 分量分别为相加后的结果。
return Vector(self.x + other.x, self.y + other.y)
# __str__ 方法:这也是 Python 中的特殊方法,用于定义对象的字符串表示形式。
# 当使用 print() 函数打印 Vector 实例时,Python 会自动调用 __str__ 方法,并将其返回值作为输出内容。
def __str__(self): # 定义 print() 时的输出
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(4, 5)
v3 = v1 + v2
print(v3) # 输出: Vector(6, 8)
"""
常见魔术方法:
__init__: 构造函数
__str__: 用户友好字符串表示(print(obj))
__repr__: 解释器友好字符串表示
__len__: 定义 len(obj) 的行为
__eq__: 重载 == 运算符
__getitem__/__setitem__: 实现索引访问(如 obj[key])
"""
# 定义一个基类 Shape
class Shape:
def area(self):
# 抛出 NotImplementedError 异常,提示子类需要实现该方法
raise NotImplementedError("子类必须实现 area 方法")
# 定义一个矩形类,继承自 Shape 类
class Rectangle(Shape):
def __init__(self, length, width):
# 初始化矩形的长和宽
self.length = length
self.width = width
def area(self):
# 计算矩形的面积
return self.length * self.width
# 定义一个圆形类,继承自 Shape 类
class Circle(Shape):
def __init__(self, radius):
# 初始化圆的半径
self.radius = radius
def area(self):
import math
# 计算圆的面积
return math.pi * self.radius ** 2
# 定义一个三角形类,继承自 Shape 类
class Triangle(Shape):
def __init__(self, base, height):
# 初始化三角形的底和高
self.base = base
self.height = height
def area(self):
# 计算三角形的面积
return 0.5 * self.base * self.height
# 多态函数,用于计算不同形状的面积
def calculate_area(shape):
# 调用传入形状对象的 area 方法
return shape.area()
# 创建不同形状的对象
rect = Rectangle(5, 10)
circle = Circle(3)
triangle = Triangle(4, 6)
# 将不同形状的对象存储在列表中
shapes = [rect, circle, triangle]
# 遍历列表,调用 calculate_area 函数计算每个形状的面积并打印结果
for shape in shapes:
# type(shape) 返回 shape 对象的类型,__name__ 属性是该类型的名称,用于获取形状对象的类型名,例如 Circle、Rectangle 等。
print(f"{type(shape).__name__} 的面积是: {calculate_area(shape)}")
# 类方法与静态方法
"""
类方法(@classmethod)接收 cls 参数,可修改类状态。
静态方法(@staticmethod)无特殊参数,用于工具函数,与类相关但无需访问实例或类属性。
"""
# 定义一个类,包含一个类属性 class_attr,一个类方法 update_class_attr 用于更新类属性的值。
# 类方法和静态方法是 Python 中类里两种特殊类型的方法.
# 在定义方式上,类方法和静态方法的定义主要区别在于装饰器和第一个参数。
# 在调用方式上,类方法和静态方法都可以通过类名直接调用,不过类方法还能通过实例调用。
# 在对类的访问权限上,类方法可以访问和修改类的属性和调用其他类方法,而静态方法不能直接访问类或实例的属性和方法。
# 在继承场景下,类方法和静态方法表现不同。在子类中调用类方法时,cls 参数会指向子类,因此可以实现基于子类的行为。静态方法在继承时不会因为子类的不同而有不同的行为,它只是简单地被继承,不会考虑类的具体类型。
# 综上所述,类方法更注重与类本身的交互,而静态方法更像是独立于类的普通函数,只是在逻辑上与类相关联。
class MyClass:
# 类属性是属于类本身的属性,所有类的实例都可以共享该属性。
class_attr = 0
class_attribute = 10
# @classmethod是一个装饰器,用于将 update_class_attr 方法标记为类方法。
# 类方法的第一个参数通常命名为 cls,它指向类本身,而不是类的实例。
@classmethod
# 方法接受两个参数:cls 表示类本身,value 是要更新类属性的值。
def update_class_attr(cls, value): # cls 指向类本身
cls.class_attr = value
@classmethod
def eric_class_method(cls):
# 访问类属性
print(f"Class attribute value: {cls.class_attribute}")
# 修改类属性
cls.class_attribute = 20
# @staticmethod是一个装饰器,用于将 utility_method 方法标记为静态方法。
# 静态方法不依赖于类或类的实例,因此不需要 self 或 cls 参数。
@staticmethod
def utility_method(a, b): # 无 self/cls 参数
# 下面这行代码会报错,不能直接访问类属性
# print(cls.class_attribute) 或 print(class_attribute)
return a + b
# 在 Python 里,如果一个函数(或者方法)没有显式地使用 return 语句返回一个值,那么它默认会返回 None。
def eric_instance_method(self):
print("这是一个实例方法")
# 这里没有 return 语句,默认返回 None
# 通过类名直接调用类方法 update_class_attr,并传入参数 5。这会将类属性 class_attr 的值更新为 5。
# 类方法和静态方法都可以通过类名直接调用,也可以通过实例调用。
MyClass.update_class_attr(5) # 通过类名调用
print(MyClass.class_attr) # 输出: 5
MyClass().update_class_attr(6) # 通过类实例调用
print(f"call by class instance:{MyClass.class_attr}") # 输出:call by class instance:6
MyClass.eric_class_method() # 输出:Class attribute value: 10
print(MyClass.class_attribute) # 输出 20
print(MyClass.class_attr) # 输出: 6
print(MyClass.utility_method(2, 3)) # 通过类名调用,输出: 5
print(MyClass().utility_method(3, 4)) # 通过实例调用,输出:7
# 使用 print 函数来输出 MyClass().eric_instance_method() 的返回值。
# 由于 eric_instance_method 方法返回 None,所以 print 函数就会输出 None。
print(MyClass().eric_instance_method()) # 输出:这是一个实例方法 \n None
# 如果不想让 print 函数输出 None,可以直接调用方法而不使用 print 函数
MyClass().eric_instance_method() # 输出:这是一个实例方法
# 下面的一行代码有错误,实例方法不能通过类名调用。
# MyClass.eric_instance_method()
# 执行上面一行代码,会出现:TypeError: MyClass.eric_instance_method() missing 1 required positional argument: 'self'
# 属性装饰器(@property)
"""
@property 将方法转换为属性,可定义 getter/setter 控制属性访问。
用于数据验证、动态计算属性(如 area)或创建只读属性。
"""
class Circle:
def __init__(self, radius):
self._radius = radius
# @property:这是 Python 的一个装饰器,用于将 radius 方法转换为一个只读属性。
# 使用 @property 装饰器后,可以像访问普通属性一样访问 radius,而不需要显式调用方法。
@property
def radius(self): # Getter
return self._radius
@radius.setter
def radius(self, value): # Setter
if value >= 0:
self._radius = value
else:
raise ValueError("半径不能为负")
@property
def area(self): # 只读属性
return 3.14 * self._radius ** 2
c = Circle(5)
print(f"get by original radius:{c.area}") # get by original radius:78.5
c.radius = 10 # 调用 setter(验证逻辑)
print(c.area) # 输出: 314.0(调用 getter)
# 抽象基类(ABC)
"""
通过 abc 模块定义抽象基类(强制子类实现特定方法)。
抽象类不能直接实例化,用于定义接口规范。
"""
# abc 模块是 Python 中用于创建抽象基类的标准库模块。
# ABC 是一个基类,用于创建抽象基类,所有的抽象基类都应该继承自 ABC。
# abstractmethod 是一个装饰器,用于将方法标记为抽象方法。
from abc import ABC, abstractmethod
# 定义了一个名为 Shape 的抽象基类,它继承自 ABC。
class Shape(ABC):
# @abstractmethod:这是一个装饰器,将 area 方法标记为抽象方法。
# 抽象方法是一种没有具体实现的方法,它只是定义了方法的签名(名称和参数),具体实现需要在子类中完成。
@abstractmethod
# 定义了一个抽象方法 area,该方法没有具体实现,只有一个 pass 语句作为占位符。
def area(self):
pass
# 定义了一个名为 Rectangle 的具体类,它继承自抽象类 Shape。
# 由于继承了抽象类,Rectangle 类必须实现抽象类中定义的所有抽象方法,否则它也会被视为抽象类,无法实例化。
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self): # 必须实现抽象方法
return self.width * self.height
# 抽象类不能被实例化,因为它包含抽象方法,而抽象方法没有具体实现。如果尝试实例化抽象类 Shape,会抛出 TypeError 异常。
# shape = Shape() # 报错:无法实例化抽象类
rect = Rectangle(3, 4)
print(rect.area()) # 输出: 12
# 在抽象类中添加一个抽象属性
# 在 Python 中,如果要在抽象类里添加抽象属性,可以借助 @property 装饰器和 @abstractmethod 装饰器结合使用
"""
实现步骤如下:
导入必要的模块:使用 abc 模块中的 ABC 和 abstractmethod 来定义抽象基类和抽象方法。
定义抽象类:让类继承自 ABC,以此表明它是一个抽象基类。
定义抽象属性:利用 @property 装饰器把方法转化为属性,再用 @abstractmethod 装饰器将其标记为抽象方法,这样该属性就成为抽象属性了。
定义具体子类:子类必须实现抽象类中的所有抽象属性和抽象方法,不然子类也会被视为抽象类,无法实例化。
"""
"""
抽象属性和抽象方法都是 Python 中抽象基类(ABC)的重要概念,它们都用于定义抽象基类的接口,要求子类必须实现,
但在使用方式、用途和语法上存在一些区别:
语法定义上的区别:
抽象属性通过结合 @property 和 @abstractmethod 装饰器来定义,本质上是将一个方法转换为属性的形式。
抽象方法使用 @abstractmethod 装饰器直接定义,是一个普通的方法签名。
调用方式的区别:
抽象属性像访问普通属性一样使用点号(.)来访问,不需要使用括号调用。
抽象方法需要像调用普通方法一样使用括号来调用,并可以传递必要的参数。
用途侧重点的区别:
抽象属性更侧重于表示对象的某种状态或特征,通常用于提供对象的只读或可读写的属性值,强调数据的获取和封装。
抽象方法更侧重于表示对象的某种行为或操作,通常用于定义对象可以执行的动作,强调行为的实现和多态性。
状态维护上的区别:
抽象属性通常与对象的状态相关联,它可能会依赖于对象的其他属性来计算或获取值。可以用于封装对象的内部状态,使得外部代码可以以统一的方式访问对象的属性。
抽象方法主要用于定义对象的行为,它不直接与对象的状态相关联,而是关注对象可以执行的操作。方法可以接受参数并返回结果,用于实现复杂的业务逻辑。
"""
from abc import ABC, abstractmethod
class Shape1(ABC): # 定义抽象类
# 定义抽象属性
# @property 和 @abstractmethod 装饰器组合使用,将 area 方法定义为抽象属性。
# 这意味着所有继承自 Shape1 的子类都必须实现 area 属性。
@property
@abstractmethod
def area(self):
pass
# 定义抽象方法
# @abstractmethod 装饰器把 perimeter 方法标记为抽象方法,子类也必须实现该方法。
@abstractmethod
def perimeter(self):
pass
class Rectangle1(Shape1): # 定义具体子类
def __init__(self, width, height):
self.width = width
self.height = height
# 实现抽象属性
# @property 装饰器将 area 方法转化为属性,实现了抽象类中定义的抽象属性 area。
@property
def area(self):
return self.width * self.height
# 实现抽象方法
def perimeter(self):
return 2 * (self.width + self.height)
# 创建 Rectangle1 类的实例
rect = Rectangle1(3, 4)
# 访问抽象属性
print(rect.area) # 直接访问属性,不需要括号, 输出: 12
# 调用抽象方法
print(rect.perimeter()) # 需要使用括号调用方法, 输出: 14
# 组合与委托
"""
组合:将其他类的实例作为属性(“有一个”关系)。
继承:表示“是一个”关系。
优先使用组合而非继承,提高代码灵活性。
组合是一种 “has - a”(有一个)的关系,即 Car 类有一个 Engine 对象;而继承是一种 “is - a”(是一个)的关系。
"""
class Engine:
def start(self):
print("引擎启动")
class Car:
def __init__(self):
# self.engine = Engine() 这行代码体现了组合的概念。
# 在 Car 类的实例化过程中,创建了一个 Engine 类的实例,并将其赋值给 Car 类实例的 engine 属性。
# 也就是说,每一个 Car 对象都 “拥有” 一个 Engine 对象。
self.engine = Engine() # 组合(而非继承)
# 定义了 Car 类的 start 方法。
def start(self):
# self.engine.start() 这行代码实现了方法的委托。
# 当调用 Car 对象的 start 方法时,实际上是调用了其内部 Engine 对象的 start 方法,从而实现了汽车启动的功能。
self.engine.start() # 委托给 Engine 对象
car = Car()
car.start() # 输出: 引擎启动