Python面向对象编程深度解析:继承、多态、魔法函数与高级实践

一、继承与多态

1.1 单继承:子类复用父类代码

继承是面向对象编程的核心机制之一,允许子类复用父类的属性和方法,同时可以扩展或修改已有功能。单继承是最简单的继承形式,一个子类只继承一个父类。

class Contact:
	all_contacts = []
	
	def __init__(self, name, email):
		self.name = name
		self.email = email
		Contact.all_contacts.append(self)

class Supplier(Contact):
	def order(self, order):
		print(f"向 {self.name} 下单:{order}")

# 使用
s = Supplier("张三", "zhangsan@example.com")
s.order("100件商品")  # 输出:向 张三 下单:100件商品
print(s.name)         # 输出:张三

在这个例子中,Supplier 类继承了 Contact 类的 __init__ 方法和 all_contacts 属性,并添加了 order 方法。

1.2 super() 调用父类构造/方法

当子类需要扩展父类的初始化逻辑时,可以使用 super() 调用父类的 __init__ 方法,避免重复代码并确保父类初始化正确执行。

class Friend(Contact):
	def __init__(self, name, email, phone):
		super().__init__(name, email)  # 调用父类构造
		self.phone*********** = Friend("李四", "lisi@example.com",***********00")
print(f.name, f.phone)  # 输出:李四 13800138000

super() 不仅用于构造函数,也可以用于普通方法。它按照方法解析顺序(MRO)调用下一个类的方法,在多重继承中尤为重要。

1.3 方法重写

子类可以重新定义父类的方法,实现自己的行为。通过 super() 可以在重写的方法中调用父类的版本,实现扩展而非完全覆盖。

class Animal:
	def eat(self):
		print("Animal can eat")

class Cat(Animal):
	def eat(self):
		super().eat()  # 调用父类方法
		print("Cat can eat chicken")

cat = Cat()
cat.eat()
# 输出:
# Animal can eat
# Cat can eat chicken

1.4 多态实现

多态是指不同类的对象对同一消息做出不同响应的能力。Python 是动态类型语言,多态天然支持——只要对象有相应的方法,就可以调用。

class Dog:
	def speak(self):
		return "汪汪"

class Cat:
	def speak(self):
		return "喵喵"

	def animal_sound(animal):
		print(animal.speak())

animal_sound(Dog())  # 输出:汪汪
animal_sound(Cat())  # 输出:喵喵

多态让代码更加灵活,无需关心对象的具体类型,只需保证对象实现了所需的方法。

1.5 多继承与MRO(方法解析顺序)

Python 支持多继承,一个子类可以同时继承多个父类。这带来了强大的代码复用能力,但也引入了方法冲突的问题。

class Father:
	def skills(self):
		print("园艺、编程")

class Mother:
	def skills(self):
		print("烹饪、音乐")

class Child(Father, Mother):
	def own_skill(self):
		print("体育")

c = Child()
c.skills()  # 输出:园艺、编程(根据MRO,Father优先)

MRO(Method Resolution Order) 是 Python 确定方法调用顺序的机制,基于 C3 线性化算法。其核心规则包括:

  • 子类优先于父类
  • 父类声明顺序保留
  • 单调性约束

可以通过 __mro__ 属性或 mro() 方法查看:

print(Child.__mro__)
# 输出:(<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>)

菱形继承问题:当多个父类继承自同一个基类时,MRO 确保每个类的方法只被调用一次。

class A:
	def method(self):
		print("A")

class B(A):
	def method(self):
		print("B")
		super().method()

class C(A):
	def method(self):
		print("C")
		super().method()

class D(B, C):
	def method(self):
		print("D")
		super().method()

d = D()
d.method()
# 输出:
# D
# B
# C
# A
print(D.__mro__)
# (D, B, C, A, object)

协作式继承:为了确保所有父类方法都被调用,父类方法中应使用 super() 形成调用链。如果无法修改父类代码,可以通过遍历 __bases____mro__ 显式调用每个父类的方法。

class Child(Parent1, Parent2):
	def onstart(self):
		for cls in self.__class__.__mro__:
			if 'onstart' in cls.__dict__:
				cls.onstart(self)

二、全套魔法函数(双下方法 __xx__

魔法函数是 Python 中名称以双下划线开头和结尾的特殊方法,用于实现对象的内置行为。掌握它们可以写出更 Pythonic 的代码。

2.1 字符串展示:__str____repr__

  • __str__:被 str()print() 调用,返回用户友好的字符串。
  • __repr__:被 repr() 调用,返回开发者友好的字符串,通常用于调试,应能通过 eval() 重建对象。
class Person:
	def __init__(self, name, age):
		self.name = name
		self.age = age

	def __str__(self):
		return f"Person: {self.name}, {self.age}岁"

	def __repr__(self):
		return f"Person('{self.name}', {self.age})"

p = Person("小明", 25)
print(p)        # 输出:Person: 小明, 25岁
print(repr(p))  # 输出:Person('小明', 25)

2.2 长度与索引:__len____getitem____setitem____delitem__

这些方法让自定义对象支持类似列表或字典的索引操作。

class MyList:
	def __init__(self, items):
		self.items = list(items)

	def __len__(self):
		return len(self.items)

	def __getitem__(self, index):
		return self.items[index]

	def __setitem__(self, index, value):
		self.items[index] = value

	def __delitem__(self, index):
		del self.items[index]

ml = MyList([1, 2, 3, 4])
print(len(ml))      # 输出:4
print(ml)        # 输出:2
ml = 99
print(ml)        # 输出:99
del ml
print(ml)        # 输出:99(原索引1变为0)

2.3 运算符重载:__add____sub____mul__

通过定义这些方法,可以让自定义对象支持 +-* 等运算符。

class Vector:
	def __init__(self, x, y):
		self.x = x
		self.y = y

	def __add__(self, other):
		return Vector(self.x + other.x, self.y + other.y)

	def __sub__(self, other):
		return Vector(self.x - other.x, self.y - other.y)

	def __mul__(self, scalar):
		return Vector(self.x * scalar, self.y * scalar)

	def __repr__(self):
		return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 输出:Vector(4, 6)
print(v2 - v1)  # 输出:Vector(2, 2)
print(v1 * 3)   # 输出:Vector(3, 6)

2.4 布尔判断:__bool__

定义 __bool__ 方法可以控制对象在布尔上下文(如 if 语句)中的行为。如果未定义,Python 会调用 __len__,长度为0则返回 False

class Account:
	def __init__(self, balance):
		self.balance = balance

	def __bool__(self):
		return self.balance > 0

acc1 = Account(100)
acc2 = Account(0)
print(bool(acc1))  # 输出:True
print(bool(acc2))  # 输出:False

2.5 迭代协议:__iter____next__

实现这两个方法可以让自定义对象支持 for 循环迭代。

class CountDown:
	def __init__(self, start):
		self.current = start

	def __iter__(self):
		return self

	def __next__(self):
		if self.current <= 0:
			raise StopIteration
		value = self.current
		self.current -= 1
		return value

for num in CountDown(5):
	print(num, end=' ')  # 输出:5 4 3 2 1

2.6 上下文魔法:__enter____exit__

实现这两个方法可以让对象支持 with 语句,自动管理资源(如文件、锁)。

class ManagedFile:
	def __init__(self, filename, mode):
		self.filename = filename
		self.mode = mode

	def __enter__(self):
		self.file = open(self.filename, self.mode)
		return self.file

	def __exit__(self, exc_type, exc_val, exc_tb):
		if self.file:
			self.file.close()
		# 返回 False 表示不抑制异常,True 表示抑制
		return False

with ManagedFile('test.txt', 'w') as f:
	f.write('Hello, World!')
# 文件自动关闭

2.7 哈希与判等:__eq____hash__

  • __eq__:定义对象相等比较逻辑。
  • __hash__:定义对象的哈希值,用于字典键和集合成员。如果定义了 __eq__,通常也需要定义 __hash__,且相等的对象哈希值应相同。
class Point:
	def __init__(self, x, y):
		self.x = x
		self.y = y

	def __eq__(self, other):
		if not isinstance(other, Point):
			return NotImplemented
		return self.x == other.x and self.y == other.y

	def __hash__(self):
		return hash((self.x, self.y))

	def __repr__(self):
		return f"Point({self.x}, {self.y})"

p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(3, 4)
print(p1 == p2)  # 输出:True
print(p1 == p3)  # 输出:False
print(hash(p1) == hash(p2))  # 输出:True
# 可以用作字典键
d = {p1: "origin"}
print(d[p2])  # 输出:origin

2.8 对象生命周期:__new____del__

  • __new__:在 __init__ 之前调用,用于创建实例(控制实例创建过程,常用于单例模式)。
  • __del__:对象被销毁时调用(析构函数),用于清理资源。
class Singleton:
	_instance = None

	def __new__(cls, *args, **kwargs):
		if cls._instance is None:
			cls._instance = super().__new__(cls)
		return cls._instance

	def __init__(self, value):
		self.value = value

	def __del__(self):
		print(f"Singleton with value {self.value} is being destroyed")

s1 = Singleton(10)
s2 = Singleton(20)
print(s1 is s2)  # 输出:True(单例)
print(s1.value)  # 输出:20(因为s2覆盖了s1)

三、OOP综合拓展

3.1 抽象基类(ABC):强制子类实现方法

抽象基类(Abstract Base Class)用于定义接口,强制子类必须实现某些方法。Python 通过 abc 模块实现。

from abc import ABC, abstractmethod

class Shape(ABC):
	@abstractmethod
	def area(self):
		pass

	@abstractmethod
	def perimeter(self):
		pass

class Circle(Shape):
	def __init__(self, radius):
		self.radius = radius

	def area(self):
		return 3.14 * self.radius ** 2

	def perimeter(self):
		return 2 * 3.14 * self.radius

# 尝试实例化抽象类会报错
# s = Shape()  # TypeError: Can't instantiate abstract class Shape

c = Circle(5)
print(c.area())       # 输出:78.5
print(c.perimeter())  # 输出:31.400000000000002

抽象基类在大型项目中非常有用,可以确保所有子类遵循统一的接口规范。

3.2 类装饰器简易用法

类装饰器是一种修改类行为的函数,接收类作为参数并返回修改后的类(或新类)。常用于添加属性、方法或修改元数据。

def add_repr(cls):
	"""为类自动添加 __repr__ 方法"""
	def __repr__(self):
		attrs = ', '.join(f"{k}={v}" for k, v in self.__dict__.items())
		return f"{cls.__name__}({attrs})"
	cls.__repr__ = __repr__
	return cls

@add_repr
class Book:
	def __init__(self, title, author):
		self.title = title
		self.author = author

b = Book("Python编程", "张三")
print(b)  # 输出:Book(title=Python编程, author=张三)

类装饰器也可以用于注册类、添加缓存、实现单例等高级功能。

3.3 三大特性总结:封装、继承、多态实战

面向对象编程的三大特性——封装、继承、多态——在实际开发中相辅相成。下面通过一个综合示例展示它们的应用:

from abc import ABC, abstractmethod

# 1. 封装:将数据和操作封装在类中
class BankAccount(ABC):
	def __init__(self, owner, balance=0):
		self._owner = owner      # 受保护属性
		self.__balance = balance # 私有属性(名称修饰)

	def deposit(self, amount):
		if amount > 0:
			self.__balance += amount
			print(f"存款 {amount},余额:{self.__balance}")

	def withdraw(self, amount):
		if 0 < amount <= self.__balance:
			self.__balance -= amount
			print(f"取款 {amount},余额:{self.__balance}")
		else:
			print("余额不足")

	def get_balance(self):
		return self.__balance

	@abstractmethod
	def describe(self):
		pass

# 2. 继承:子类复用父类代码并扩展
class SavingsAccount(BankAccount):
	def __init__(self, owner, balance=0, interest_rate=0.02):
		super().__init__(owner, balance)
		self.interest_rate = interest_rate

	def apply_interest(self):
		interest = self.get_balance() * self.interest_rate
		self.deposit(interest)
		print(f"利息 {interest:.2f} 已添加")

	def describe(self):
		return f"储蓄账户 - 户主:{self._owner},利率:{self.interest_rate*100}%"

class CheckingAccount(BankAccount):
	def __init__(self, owner, balance=0, overdraft_limit=1000):
		super().__init__(owner, balance)
		self.overdraft_limit = overdraft_limit

	def withdraw(self, amount):
		if amount <= self.get_balance() + self.overdraft_limit:
		# 重写取款方法,允许透支
		if amount > self.get_balance():
			print("使用透支额度")
			super().withdraw(amount)
		else:
			print("超过透支限额")

	def describe(self):
		return f"支票账户 - 户主:{self._owner},透支限额:{self.overdraft_limit}"

	# 3. 多态:不同对象对同一消息做出不同响应
	def show_account_info(account):
		print(account.describe())
		print(f"当前余额:{account.get_balance()}")

# 使用
savings = SavingsAccount("Alice", 1000, 0.03)
checking = CheckingAccount("Bob", 500, 2000)

savings.deposit(500)
savings.apply_interest()
show_account_info(savings)
# 输出:
# 存款 500,余额:1500
# 利息 45.00 已添加
# 存款 45,余额:1545
# 储蓄账户 - 户主:Alice,利率:3.0%
# 当前余额:1545

checking.withdraw(2000)  # 使用透支额度
show_account_info(checking)
# 输出:
# 使用透支额度
# 取款 2000,余额:-1500
# 支票账户 - 户主:Bob,透支限额:2000
# 当前余额:-1500

总结

Python 的面向对象编程提供了丰富的机制来构建可维护、可扩展的代码:

  • 继承 通过单继承和多继承实现代码复用,super() 和 MRO 确保方法调用的正确性。
  • 多态 让代码更加灵活,无需关心对象的具体类型。
  • 魔法函数 赋予自定义对象与内置类型一致的行为,从字符串展示到运算符重载,从迭代到上下文管理。
  • 抽象基类 强制子类实现接口,保证代码的规范性。
  • 类装饰器 提供了一种优雅的方式修改类行为。

在实际开发中,应遵循“组合优于继承”的原则,谨慎使用多继承,优先使用混入(Mixin)模式。理解这些核心概念,将帮助你写出更 Pythonic、更健壮的代码。

更多推荐