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 = name

if __name__ == '__main__':
    dog = Adog("小黑")
    print(dog.name)  # 直接访问属性:小黑

    # 动态设置属性
    dog.age = 2
    print(dog.age)  # 2

    # 判断属性是否存在
    print(hasattr(dog, "age"))  # True

    # 删除属性
    delattr(dog, "age")
    print(hasattr(dog, "age"))  # False

    # 重新设置并获取属性
    setattr(dog, "age", 3)
    print(hasattr(dog, "age"))  # True
    print(getattr(dog, "age"))  # 3

三、动态属性处理(Model 类示例)

通过__new__魔术方法动态生成类的属性、property( getter/setter )和__repr__方法,简化类的定义。

1. 核心逻辑
  • 定义Model类,通过__new__方法在类创建时动态处理属性:
    1. 从子类的__all_fields__获取需要的属性列表;
    2. 检查传入的关键字参数是否合法(仅允许__all_fields__中的属性);
    3. 为每个属性生成私有变量,并通过property绑定 getter 和 setter;
    4. 动态生成__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)}")

        # 动态生成属性和property
        for 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 = name
        self.age = age

p = 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 = name
        self.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 = name
        self.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 = None

    def __init__(self, name, age):
        # 注意:若实例已存在,__init__仍会被调用,可能覆盖属性
        self.name = name
        self.age = age

    def __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 + 1
        return instance

    @classmethod
    def 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, abstractmethod

class Procurement(ABC):
    def __init__(self, price):
        self.price = price
        self.next_approval = None

    def set_next_approval(self, next_approval):
        self.next_approval = next_approval
        return next_approval  # 支持链式调用

    @abstractmethod
    def 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 = approval0

    def 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)

以上整理完整覆盖了您例题中的单例模式、元类应用、责任链模式等核心知识点,并通过代码示例与逻辑说明强化理解。

相关推荐
杨DaB2 小时前
【SpringMVC】拦截器,实现小型登录验证
java·开发语言·后端·servlet·mvc
近津薪荼2 小时前
c++详解(宏与内联函数,nullptr)
开发语言·c++
淮北4943 小时前
STL学习(十一、常用的算数算法和集合算法)
c++·vscode·学习·算法
糖葫芦君3 小时前
玻尔兹曼分布与玻尔兹曼探索
人工智能·算法·机器学习
摸鱼仙人~3 小时前
Redis 数据结构全景解析
数据结构·数据库·redis
TT-Kun3 小时前
PyTorch基础——张量计算
人工智能·pytorch·python
天若有情6737 小时前
【python】Python爬虫入门教程:使用requests库
开发语言·爬虫·python·网络爬虫·request
IT北辰8 小时前
用Python+MySQL实战解锁企业财务数据分析
python·mysql·数据分析
Lucky高8 小时前
selenium(WEB自动化工具)
python