Python Day17 面向对象 及例题分析
一、多态
1. 核心概念
多态是面向对象的核心概念,指同一个操作在不同对象上表现出不同行为。
2. 实现方式
- 传统实现:通过继承中的方法重写实现(子类重写父类方法,不同子类表现不同)。
- Python 中的特殊实现:
由于 Python 是 “动态语言”,多态不一定依赖继承,只要两个对象有相同的方法名但行为不同,即可称为多态,这一特性被称为 “鸭子模型”(“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子”)。
Python 天生支持多态。
3. 示例代码
class Cat:def speak(self):print("喵呜~~")class Dog:def speak(self):print("汪汪汪~~")class Sheep:def speak(self):print("灰太狼来啦~~")if __name__ == '__main__':cat = Cat()dog = Dog()sheep = Sheep()animals = [cat, dog, sheep]# 同一个操作speak(),不同对象表现不同for animal in animals:animal.speak() # 输出:喵呜~~ / 汪汪汪~~ / 灰太狼来啦~~
二、反射
1. 核心概念
反射指程序运行期间动态操作对象属性(获取、设置、删除、判断是否存在)。
2. 常用函数(均接收字符串类型的属性名)
函数 | 作用 |
---|---|
getattr(obj, 'name') | 获取对象obj 中属性name 的值 |
setattr(obj, 'name', value) | 给对象obj 的属性name 设置值value |
delattr(obj, 'name') | 删除对象obj 中的属性name |
hasattr(obj, 'name') | 判断对象obj 中是否存在属性name (返回布尔值) |
3. 示例代码
class Adog:def __init__(self, name):self.name = nameif __name__ == '__main__':dog = Adog("小黑")print(dog.name) # 直接访问属性:小黑# 动态设置属性dog.age = 2print(dog.age) # 2# 判断属性是否存在print(hasattr(dog, "age")) # True# 删除属性delattr(dog, "age")print(hasattr(dog, "age")) # False# 重新设置并获取属性setattr(dog, "age", 3)print(hasattr(dog, "age")) # Trueprint(getattr(dog, "age")) # 3
三、动态属性处理(Model 类示例)
通过__new__
魔术方法动态生成类的属性、property
( getter/setter )和__repr__
方法,简化类的定义。
1. 核心逻辑
- 定义
Model
类,通过__new__
方法在类创建时动态处理属性:- 从子类的
__all_fields__
获取需要的属性列表; - 检查传入的关键字参数是否合法(仅允许
__all_fields__
中的属性); - 为每个属性生成私有变量,并通过
property
绑定 getter 和 setter; - 动态生成
__repr__
方法,格式化对象的字符串表示。
- 从子类的
2. 示例代码
class Model:def __new__(cls, *args, **kwargs):instance = super().__new__(cls)# 获取子类定义的所有属性fields = cls.__all_fields__# 检查关键字参数合法性for key in kwargs:if key not in fields:raise KeyError(f"不识别关键字{key},允许的关键字:{','.join(fields)}")# 动态生成属性和propertyfor field in fields:value = kwargs.get(field) # 默认为None# 定义私有变量(格式:_类名__属性名)setattr(instance, f"_{cls.__name__}__{field}", value)# 生成getter(获取私有变量值)getter = (lambda x: lambda self: getattr(self, f"_{cls.__name__}__{x}"))(field)# 生成setter(设置私有变量值)setter = (lambda x: lambda self, val: setattr(self, f"_{cls.__name__}__{x}", val))(field)# 绑定property到类setattr(cls, field, property(getter, setter))# 动态生成__repr__方法(格式化对象信息)prefix = f"_{cls.__name__}__"setattr(cls, "__repr__", lambda self: f"{self.__class__.__name__}({ {k.removeprefix(prefix):v for k,v in self.__dict__.items()} })")return instance# 子类继承Model,仅需定义__all_fields__
class Human(Model):__all_fields__ = ('name', 'age', 'gender', 'tel', 'email')if __name__ == '__main__':human = Human(name='小光', age=20, gender='<UNK>', tel='<UNK>', email='<UNK>')print(human.name, human.tel) # 小光 <UNK>print(human) # Human({'name': '小光', 'age': 20, 'gender': '<UNK>', 'tel': '<UNK>', 'email': '<UNK>'})
四、元类
1. 核心概念
- 元类是 “描述类的类型”,用
type
表示(所有类都是type
的实例)。 - 作用:
a) 创建类;
b) 控制类的创建过程(如动态添加属性 / 方法、限制类的实例化等)。
2. type
的用法
type
有两种核心用法:
- 获取对象类型:
type(obj)
返回对象obj
的类型(类)。 - 动态创建类:
type(name, bases, kwargs)
直接创建一个类,参数说明:name
:类名(字符串);bases
:父类元组(无父类时为空元组);kwargs
:类的属性和方法(字典)。
3. 用type
创建类的示例
# 用type创建Dog1类(类名:Dog1,无父类,包含__init__、eat、speak方法)
Dog1 = type('Dog1', # 类名(), # 父类元组(空){"__init__": lambda self, name: setattr(self, "name", name), # 初始化方法'eat': lambda self: print('狗在吃骨头!'), # 自定义方法'speak': lambda self: print('汪汪汪!') # 自定义方法}
)# 使用创建的类
dog = Dog1("小黑")
dog.speak() # 汪汪汪!
print(dog.name) # 小黑
4. 自定义元类(通过metaclass
控制类的创建)
通过metaclass
参数指定元类,可在类创建时插入自定义逻辑。元类需继承type
,核心魔术方法:
__new__
:创建类(返回类的实例);__init__
:初始化类(给类添加属性 / 方法);__call__
:控制类的实例化(创建类的对象)。
示例 1:给类自动添加__repr__
和私有类属性
class Repr(type):"""元类:给类添加__repr__方法和私有类属性__logo"""def __new__(cls, name, bases, kwargs):# 动态添加__repr__方法(格式化对象信息)kwargs['__repr__'] = lambda self: f"{self.__class__.__name__}({self.__dict__})"# 动态添加私有类属性(格式:_类名__logo)kwargs[f"_{name}__logo"] = 'QIKU'# 创建并返回类return super().__new__(cls, name, bases, kwargs)# 使用Repr元类
class Person(metaclass=Repr):def __init__(self, name, age):self.name = nameself.age = agep = Person("小明", 18)
print(p) # Person({'name': '小明', 'age': 18})
print(Person._Person__logo) # QIKU(私有类属性)
示例 2:单例模式(类仅能创建一个对象)
class Singleton(type):"""元类:确保类仅能实例化一个对象"""def __call__(self, *args, **kwargs):# 定义私有类属性存储唯一实例(格式:_类名__instance)instance_attr = f"_{self.__name__}__instance"# 若实例不存在,则创建并保存;若存在,直接返回if not hasattr(self, instance_attr):instance = super().__call__(*args, **kwargs) # 调用父类创建对象setattr(self, instance_attr, instance) # 保存实例return getattr(self, instance_attr) # 返回唯一实例# 同时添加__repr__和__logo(复用Repr的逻辑)def __new__(cls, name, bases, kwargs):kwargs['__repr__'] = lambda self: f"{self.__class__.__name__}({self.__dict__})"kwargs[f"_{name}__logo"] = 'QIKU'return super().__new__(cls, name, bases, kwargs)# 使用Singleton元类(单例)
class Person(metaclass=Singleton):def __init__(self, name, age):self.name = nameself.age = age# 测试单例:两个对象指向同一实例
p1 = Person("糕糕", 20)
p2 = Person("曹操", 30) # 虽传入新参数,但不会创建新对象
print(p1) # Person({'name': '糕糕', 'age': 20})(p2与p1相同)
print(p1 is p2) # True(同一实例)
五、类与元类中的核心魔术方法对比
魔术方法 | 类中作用 | 元类中作用 |
---|---|---|
__new__ | 创建类的对象(实例) | 创建类(类本身) |
__init__ | 初始化对象的属性 | 初始化类的属性 / 方法 |
__call__ | 使对象可调用(如obj() ) | 控制类的实例化(创建对象) |
以上整理完整覆盖了您笔记中的多态、反射、动态属性处理、元类定义与应用等核心知识点,并通过代码示例与逻辑说明强化理解。
一、单例模式(多种实现方式)
单例模式确保一个类只有一个实例,并提供全局访问点。
1. 装饰器实现
def Singleton(cls):_instances = {}def wrapper(*args, **kwargs):if cls not in _instances:_instances[cls] = cls(*args, **kwargs)return _instances[cls]return wrapper@Singleton
class A:def __init__(self, name):self.name = name# 测试
a = A(1)
b = A(3)
print(a.name) # 1(单例模式,参数仅首次生效)
print(b.name) # 1
2. 元类实现
class Singleton1(type):def __call__(cls, *args, **kwargs):field = f'_{cls.__name__}__instance'if not hasattr(cls, field):instance = super().__call__(*args, **kwargs)setattr(cls, field, instance)return getattr(cls, field)class B(metaclass=Singleton1):def __init__(self, name, age):self.name = nameself.age = age# 测试
b1 = B("Alice", 20)
b2 = B("Bob", 30)
print(b1.name, b1.age) # Alice 20
print(b2.name, b2.age) # Alice 20(单例模式,参数仅首次生效)
3. __new__
方法实现
class B:_instance = Nonedef __init__(self, name, age):# 注意:若实例已存在,__init__仍会被调用,可能覆盖属性self.name = nameself.age = agedef __new__(cls, *args, **kwargs):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instance# 测试
b1 = B("Alice", 20)
b2 = B("Bob", 30)
print(b1.name, b1.age) # Bob 30(__init__被二次调用,覆盖属性)
print(b2.name, b2.age) # Bob 30
二、元类应用:类属性转换为大写
将类中的类属性名全部转换为大写,并通过大写名称访问原值。
class V(type):def __new__(cls, name, bases, dct):new_dct = {}for k, v in dct.items():new_dct[k.upper()] = v # 将属性名转为大写return super().__new__(cls, name, bases, new_dct)class A(metaclass=V):name = "a"sex = "m"print(A.NAME) # a
print(A.SEX) # m
三、元类应用:实例计数器
跟踪使用该元类创建的所有类的实例数量。
class CountingMeta(type):__global_instance_dict__ = {} # 存储类名到实例数量的映射def __call__(cls, *args, **kwargs):instance = super().__call__(*args, **kwargs)count = cls.__global_instance_dict__.get(cls.__name__, 0)cls.__global_instance_dict__[cls.__name__] = count + 1return instance@classmethoddef get_instance_count(cls, target_cls):"""返回指定类的实例数量"""return cls.__global_instance_dict__.get(target_cls.__name__, 0)class A(metaclass=CountingMeta):pass# 测试
a1 = A()
a2 = A()
a3 = A()
print(CountingMeta.get_instance_count(A)) # 3
四、责任链模式:采购审批流程
根据采购金额自动选择相应的审批者(直接领导→部门经理→总经理→董事长)。
1. 抽象处理器基类
from abc import ABC, abstractmethodclass Procurement(ABC):def __init__(self, price):self.price = priceself.next_approval = Nonedef set_next_approval(self, next_approval):self.next_approval = next_approvalreturn next_approval # 支持链式调用@abstractmethoddef approval(self):pass
2. 具体处理器实现
class Approval0(Procurement): # 直接领导(<5000)def approval(self):if self.price < 5000:print("申请直接领导审批")else:self.next_approval.approval()class Approval1(Procurement): # 部门经理(<30000)def approval(self):if self.price < 30000:print("申请部门经理审批")else:self.next_approval.approval()class Approval2(Procurement): # 总经理(<200000)def approval(self):if self.price < 200000:print("申请总经理审批")else:self.next_approval.approval()class Approval3(Procurement): # 董事长(≥200000)def approval(self):print("申请董事长审批")
3. 流程管理器
class Process:def __init__(self, price):self.price = price# 构建责任链approval0 = Approval0(price)approval1 = Approval1(price)approval2 = Approval2(price)approval3 = Approval3(price)approval0.set_next_approval(approval1) \.set_next_approval(approval2) \.set_next_approval(approval3)self.__handler = approval0def process(self):return self.__handler.approval()
4. 测试
if __name__ == "__main__":Process(4000).process() # 申请直接领导审批Process(15000).process() # 申请部门经理审批Process(80000).process() # 申请总经理审批Process(250000).process() # 申请董事长审批
五、元类应用:自动生成方法
根据类的__fields__
属性自动生成__init__
和__str__
方法。
1. 元类实现
class AutoMethodsMeta(type):def __new__(cls, name, bases, dct):# 获取字段列表fields = dct.get('__fields__', [])# 生成__init__方法def __init__(self, *args, **kwargs):# 处理位置参数if args:if len(args) > len(fields):raise TypeError(f"{name}接受最多{len(fields)}个位置参数")for i, value in enumerate(args):setattr(self, fields[i], value)# 处理关键字参数for key, value in kwargs.items():if key not in fields:raise KeyError(f"未知参数'{key}',有效参数:{fields}")setattr(self, key, value)# 检查必填字段for field in fields:if not hasattr(self, field):setattr(self, field, None)# 生成__str__方法def __str__(self):attrs = ", ".join(f"{field}={getattr(self, field)!r}" for field in fields)return f"{name}({attrs})"# 更新类属性dct['__init__'] = __init__dct['__str__'] = __str__return super().__new__(cls, name, bases, dct)
2. 使用示例
class ExampleClass(metaclass=AutoMethodsMeta):__fields__ = ['name', 'age']# 测试
obj = ExampleClass(name='John', age=30)
print(obj) # ExampleClass(name='John', age=30)
以上整理完整覆盖了您例题中的单例模式、元类应用、责任链模式等核心知识点,并通过代码示例与逻辑说明强化理解。