Python 类和对象:详细讲解(下篇)
15. 接口和协议(Interfaces and Protocols)
15.1 什么是接口?
接口是一个类必须遵循的规则或约定,它定义了类应该具备哪些方法,但不提供具体的实现。在 Python 中,接口常用在规定某些类必须实现特定的方法。通过接口,不同的类可以被相同的代码调用,只要它们实现了接口的要求。
15.2 协议的基本概念
协议是 Python 中的一种接口定义方式,常用于规定一个类应该具备哪些方法。协议是“非正式”的接口,它不要求显式地继承任何东西,只需要类实现了协议中的方法。
例子:定义飞行协议
from typing import Protocol # 定义一个飞行协议,规定类必须有 fly 方法 class Flyer(Protocol): def fly(self) -> None: pass # 定义一个 Bird 类,它实现了 fly 方法 class Bird: def fly(self) -> None: # 注意 -> None 表示这个方法不返回任何值 print("Bird is flying") # 定义一个 Airplane 类,它也实现了 fly 方法 class Airplane: def fly(self) -> None: print("Airplane is flying") # 定义一个函数,这个函数接受任何有 fly 方法的对象 def make_fly(flyer: Flyer): flyer.fly() # 创建 Bird 和 Airplane 的实例,并传递给 make_fly 函数 bird = Bird() plane = Airplane() make_fly(bird) # 输出: Bird is flying make_fly(plane) # 输出: Airplane is flying
详细解释
- Flyer(Protocol):
Flyer
是一个协议类,它定义了所有实现此协议的类必须具备的fly
方法。 - fly(self) -> None:
-> None
的意思是这个方法不返回任何值。None
是 Python 的一种特殊类型,表示什么都没有。 - make_fly(flyer: Flyer): 这个函数接受任何实现
Flyer
协议的对象作为参数。无论是Bird
还是Airplane
,只要它们实现了fly
方法,就可以传给这个函数。
输出示例
Bird is flying Airplane is flying
这个示例展示了 Bird
和 Airplane
类如何实现同样的 fly
方法,使得它们都可以被 make_fly
函数调用。
16. 装饰器模式(Decorator Pattern)
16.1 什么是装饰器?
装饰器是 Python 中的一个强大特性,允许你在不修改原始函数的情况下,为函数添加额外的功能。装饰器本质上是一个函数,它接收另一个函数作为参数,并返回一个新的函数。
例子:简单的函数装饰器
# 定义一个简单的装饰器函数 def simple_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() # 调用原始函数 print("Something is happening after the function is called.") return wrapper # 使用装饰器 @simple_decorator # @符号表示我们使用simple_decorator来装饰say_hello函数 def say_hello(): print("Hello!") # 调用被装饰的函数 say_hello()
详细解释
- @simple_decorator: 这个语法糖(简便写法)表示将
say_hello
函数传递给simple_decorator
装饰器,相当于say_hello = simple_decorator(say_hello)
。 - wrapper(): 装饰器内部定义的
wrapper
函数包裹了原始的say_hello
函数,在调用say_hello
时,会先执行wrapper
内的代码。 - func():
func
是原始的say_hello
函数,通过调用它,我们在wrapper
中执行了原始函数的功能。
输出示例
Something is happening before the function is called. Hello! Something is happening after the function is called.
16.2 为什么 @ 符号放在函数定义上面?
- @符号的作用: 它是用来简化装饰器应用的。如果没有
@
符号,你需要手动将函数传给装饰器。使用@
符号时,装饰器会在函数定义之后立即应用,不需要手动传递。
代码对比
# 使用 @ 语法糖 @simple_decorator def say_hello(): print("Hello!") # 不使用 @ 语法糖,等同于上面的代码 def say_hello(): print("Hello!") say_hello = simple_decorator(say_hello)
17. 上下文管理器(Context Managers)
17.1 什么是上下文管理器?
上下文管理器用于在一段代码运行前后自动管理资源,比如文件、网络连接等。上下文管理器确保资源在使用后被正确释放,避免资源泄漏问题。
示例:使用上下文管理器管理文件
# 使用上下文管理器打开文件 with open('example.txt', 'w') as file: file.write('Hello, World!') # 这个文件会在 with 语句块结束时自动关闭
17.2 自定义上下文管理器
你可以通过定义 __enter__
和 __exit__
方法来自定义上下文管理器。这两个方法分别在上下文管理器的进入和退出时执行。
示例:自定义上下文管理器
class MyContextManager: def __enter__(self): print("Entering the context") return self def __exit__(self, exc_type, exc_val, exc_tb): print("Exiting the context") if exc_type: print(f"Exception type: {exc_type}") print(f"Exception value: {exc_val}") print(f"Traceback: {exc_tb}") return True # 处理异常后,继续执行 # 使用自定义上下文管理器 with MyContextManager(): print("Inside the context") raise ValueError("Oops!") # 故意引发一个异常
详细解释
- enter: 当你进入
with
语句时,__enter__
方法会被自动调用。你可以在这里做一些初始化操作。 - exit: 当
with
语句结束时,__exit__
方法会被调用。这个方法接受三个参数:exc_type
(异常类型)、exc_val
(异常值)、exc_tb
(异常的追踪信息)。这些参数用于处理在with
语句块内发生的任何异常。 - return True: 如果
__exit__
返回True
,异常将被抑制,不会向外抛出。如果返回False
或者不返回,异常将会被继续抛出。
输出示例
Entering the context Inside the context Exiting the context Exception type: <class 'ValueError'> Exception value: Oops! Traceback: <traceback object at 0x...>
18. 元类(Metaclasses)
18.1 什么是元类?
元类是用来创建类的“类”。普通类是用来创建对象的,而元类是用来创建类的。元类通常用于自动修改类的定义或行为。
示例:简单的元类
class MyMeta(type): def __new__(cls, name, bases, dct): print(f"Creating class {name}") return super().__new__(cls, name, bases, dct) class MyClass(metaclass=MyMeta): pass # 创建 MyClass 的实例 obj = MyClass()
详细解释
- type:
type
是 Python 内置的元类,用于创建所有的类。MyMeta
继承自type
,我们通过__new__
方法来控制类的创建。 - new(cls, name, bases, dct):
__new__
是一个特殊的方法,它在__init__
之前被调用,用于创建类。cls
是元类本身,name
是类的名称,bases
是类的基类(父类),dct
是类的属性和方法的字典。
- metaclass=MyMeta: 当你定义
MyClass
时,Python 会使用MyMeta
元类来创建MyClass
类。
输出示例
Creating class MyClass
当你定义 MyClass
时,会输出 Creating class MyClass
,表示元类 MyMeta
正在创建 MyClass
。
19. 面向对象设计原则(SOLID Principles)
19.1 SOLID 原则简介
SOLID 是面向对象设计的五大原则,用来编写可维护、可扩展的代码。我们一条一条来看。
19.1.1 单一职责原则(SRP)
单一职责原则(Single Responsibility Principle)要求一个类应该只负责一件事。这样可以让类更简单、更易维护。
示例:单一职责原则
class ReportGenerator: def generate(self): print("Generating report") class ReportSaver: def save(self): print("Saving report")
ReportGenerator
负责生成报告。ReportSaver
负责保存报告。每个类都有明确的职责,不会混在一起。
19.1.2 开放/封闭原则(OCP)
开放/封闭原则(Open/Closed Principle)要求软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。
示例:开放/封闭原则
class Shape: def area(self): pass class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * (self.radius ** 2) class Rectangle(Shape): def __init__(self, length, width): self.length = length self.width = width def area(self): return self.length * self.width
- 通过继承
Shape
类,我们可以创建新的形状类,而不需要修改现有代码。
19.1.3 里氏替换原则(LSP)
里氏替换原则(Liskov Substitution Principle)要求子类对象必须能够替换基类对象,而不会影响程序的正确性。
示例:里氏替换原则
class Bird: def fly(self): print("Bird is flying") class Penguin(Bird): def fly(self): raise NotImplementedError("Penguins cannot fly") # 这种设计违反了里氏替换原则,因为企鹅不能飞,但它继承了能飞的鸟类
Penguin
不能替代Bird
,因为企鹅不会飞,这违反了里氏替换原则。
19.1.4 接口隔离原则(ISP)
接口隔离原则(Interface Segregation Principle)要求类不应该被强迫实现它不需要的接口或方法。
示例:接口隔离原则
class Workable: def work(self): pass class Eatable: def eat(self): pass class Worker(Workable, Eatable): def work(self): print("Working") def eat(self): print("Eating") class Robot(Workable): def work(self): print("Working") # Robot 只实现了它需要的接口,而不是所有接口
Robot
只实现了Workable
接口,而不需要实现Eatable
接口。
19.1.5 依赖倒置原则(DIP)
依赖倒置原则(Dependency Inversion Principle)要求高层模块不应该依赖于低层模块,而应该依赖于抽象(接口)。
示例:依赖倒置原则
class Keyboard: def type(self): return "Typing" class Monitor: def display(self): return "Displaying" class Computer: def __init__(self, keyboard: Keyboard, monitor: Monitor): self.keyboard = keyboard self.monitor = monitor def operate(self): print(self.keyboard.type()) print(self.monitor.display())
Computer
依赖于Keyboard
和Monitor
抽象,而不是它们的具体实现,这使得更换这些组件变得容易。
以上就是关于【Python篇】Python 类和对象:详细讲解(下篇)的内容啦,各位大佬有什么问题欢迎在评论区指正,您的支持是我创作的最大动力!❤️