Python面向对象-面向对象进阶
2025-9-2
| 2025-9-26
Words 8364Read Time 21 min
type
status
date
slug
summary
tags
category
icon
password

📝 面向对象的成员

1、变量(Data Members)

1.1、总览速查表

名称
定义位置
归属
访问方式
生命周期
类变量
类体里,方法外
类本身
类名.变量 或 实例.变量
程序运行期间
实例变量
方法内,self. 前缀
每个实例
实例.变量
实例创建→销毁
局部变量
方法/函数内部
栈帧
仅函数内部
调用→返回
私有变量
__var_var
实例/类
类内 self.__var,类外受限
同实例变量

1.2、类变量(Class Variable)

  1. 定义位置:位于 类体内部、所有方法外部(即直接写在类名下,且前面无 self.)。
  1. 生命周期
      • 创建:类被 定义/导入 时立即生成,直到程序结束才销毁。
      • 销毁:进程结束或类被显式 del 时。
  1. 共享性
      • 所有实例和类本身共享同一份内存
      • 通过 类名.变量实例.变量 都可访问;实例修改会 创建同名实例变量 覆盖,但类变量本身不变。

1.3、实例变量(Instance Variable)

  1. 定义位置:在 实例方法内部 且通过 self.变量名 = 值 的形式绑定,通常放在 __init__ 中,也允许在其它方法里动态添加。
  1. 生命周期
      • 创建:实例化对象(obj = Class(...))时随 __init__ 或后续赋值产生。
      • 销毁:该对象被垃圾回收(无引用)时自动释放。
  1. 隔离性
      • 每个实例拥有独立的一份内存
      • 实例之间互不影响;修改一个实例变量不会影响其它实例。

1.4、局部变量(local variable)

  1. 定义位置:出现在类的方法体内部(包括实例方法、类方法、静态方法)或函数体内部,且前面没有 self.类名前缀
  1. 生命周期
      • 创建:执行到变量赋值语句时。
      • 销毁:方法/函数执行结束(return 或抛出异常)即被垃圾回收。
  1. 隔离性
      • 每次方法调用都重新创建,不共享给其它调用或实例。
      • 作用域仅限于当前栈帧,外部无法访问。

1.5、私有变量(private variable)

  1. 定义位置:在类的方法内部,以 双下划线前缀 __变量名单下划线前缀 _变量名 绑定到实例或类本身。
      • __var(双下划线)触发「名称重整」,类外无法直接访问;
      • _var(单下划线)仅约定私有,仍可直接访问。
  1. 生命周期:与所属实例或类的生命周期一致
      • 创建:实例化或类定义时赋值;
      • 销毁:实例/类被垃圾回收时释放。
  1. 隔离性
      • 作用域:仅在类内部可见(双下划线通过名称重整强制隔离)。
      • 每实例/每类独立一份,与其他实例/类互不干扰。

1.6、五大易错点

  1. 同名掩盖:读时“就近”,写时“新建”
    1. 易错:误以为 a.x = 99 会修改类变量。
  1. __私有 名称重整:读/写都要用重整后的名字
    1. 子类内部读写双下划线变量,必须加 _父类__前缀
  1. 继承链查找顺序:只读不改时遵循 MRO
    1. C.x = 2 则会在 C 类本身 新建变量,不会改动 P.x
  1. 实例写类变量:需显式指定类名
    1. 可变类变量陷阱:读引用,写重绑
      1. 若执行 Box.items = [7] 则重绑到新列表,旧列表与实例无影响。

    2、方法(Method Members)

    2.1、总览速查表

    方法类型
    装饰器
    默认第一个形参
    归属
    访问场景
    典型用途
    实例方法
    self(当前对象)
    实例
    需要对象状态
    读写属性、业务逻辑
    类方法
    @classmethod
    cls(当前类)
    无需对象但需类级数据
    工厂方法、修改类变量
    静态方法
    @staticmethod
    既不需要对象也不需要类
    工具函数、校验逻辑

    2.2、实例方法(Instance Method)

    1. 定义在类体内部、未加任何装饰器的普通函数;其第一个形参必须是 self(名字可改,但约定为 self),代表当前对象本身。
    1. 绑定与调用创建:类被定义后,函数对象即被绑定为实例方法。调用:
        • 实例对象调用:obj.method()
        • 类名手动调用:Class.method(obj, *args)(极少用)。
    1. 作用域与访问权限作用域:方法体内部可直接访问并修改实例变量self.var)和类变量Class.varself.__class__.var)。无法访问其他实例的私有变量(除非显式传参)。
    1. 生命周期与实例对象同生同灭;实例销毁后,该方法仍可被类再次调用(但需新实例)。
    1. 示例
      1. 总结:实例方法以 self 为入口,只能通过对象调用,用于读写该对象自身状态或调用类级资源。

      2.3、类方法(Class Method)

      1. 定义与语法用装饰器 @classmethod 声明,第一个形参必须是 cls(约定俗成),指向当前类对象本身。
        1. 绑定与调用绑定:类加载时自动把函数包装成类方法对象,与实例无关。调用方式
            • 类名调用:Foo.cm(x)
            • 实例调用:obj.cm(x)(等价于 Foo.cm(x),因为 cls=Foo)。
        1. 作用域与权限可读写类变量 (cls.var),无法直接访问实例变量(除非显式传入实例)。可继承:子类调用时 cls 就是子类,天然支持多态。
        1. 生命周期与类同生同灭;类被垃圾回收后方法才消失。
        1. 常见用途
          1. 场景
            示例
            备选构造器(工厂方法)
            datetime.fromtimestamp()
            统计/配置 等需要类级共享数据
            记录实例个数、全局默认配置
            在子类中自动拿到正确子类
            避免硬编码类名
        1. 实战示例
          1. 工厂方法(备用构造器)
            1. 💡
              方法内部用 cls(data["name"]) 调用了真正的构造函数 __init__,并返回新建好的实例。调用者无需直接写 Person(...),只要传字典即可:p = Person.from_dict({"name": "Alice"})等价于p = Person("Alice")
          2. 子类继承时自动拿到正确子类
            1. 💡
              注意:如果用 Base() 硬编码,子类就得不到正确类型。 在类方法里 永远不要硬编码类名去实例化,应当用 cls(...),保证“谁调用,就生成谁类型的对象”。
        1. 容易被忽略的细节
          1. 要点
            说明
            描述器协议
            classmethod 对象实现了 __get__,因此只能 挂在类属性上;如果你把它赋值给实例属性,再访问时不会触发描述器,得到的只是裸函数。
            不能跟 staticmethod 混用
            @classmethod 必须紧贴函数,顺序错会失效:<br>@classmethod @staticmethod → 报错或行为异常。
            绑定行为
            类方法一旦通过 子类 访问,cls 就是 子类本身,这让它在框架代码里特别有用。
            与元类配合
            在元类里用 classmethod 可以给 元类自身 定义类方法(此时 cls 是元类)。
        1. 总结:类方法以 cls 为入口,操作类本身或提供类级工厂,与具体实例无关,可被类或实例调用。

        2.4、静态方法(@staticmethod)

        1. 定义用 @staticmethod 装饰,无默认形参(既无 self 也无 cls),本质上只是一个放在类命名空间里的普通函数
          1. 绑定与调用不绑定任何对象或类,不会自动传入 self/cls。调用方式
              • 类名调用:Foo.util(1,2)
              • 实例调用:obj.util(1,2)(与类名调用等价)。
          1. 作用域与隔离性不能直接访问实例变量或类变量(除非显式传参)。仅借类的命名空间做逻辑归类,与类/实例状态完全解耦
          1. 生命周期与类同生同灭;类被卸载时方法随之消失。
          1. 常见用途
            1. 场景
              示例
              工具函数 与类相关,但不需要访问类或实例状态
              数据校验、单位换算、格式转换
              把旧函数“挂”进类命名空间
              保持代码组织结构清晰
              接口/协议一致性
              classmethod 一起提供多态入口
          1. 实战示例
            1. 工具函数
              1. 输入校验(与枚举配合)
                1. 组织代码:把全局函数收进类
                1. 容易被忽略的细节
                  1. 要点
                    说明
                    描述器协议
                    classmethod 一样,只能 挂在类属性上;赋值给实例属性再访问时,不会触发描述器,得到的是裸函数。
                    无绑定行为
                    静态方法 不会自动传 selfcls,所以内部如果 硬编码类名,子类化时可能失效;此时应改用 classmethod
                    与继承的关系
                    静态方法 不参与动态派生,子类覆盖后,父类版本 不会自动引用子类
                    单元测试友好
                    因为无隐式状态,纯函数式 的静态方法很容易做单元测试。
                1. 总结:静态方法既不依赖实例不依赖类,只是借类的“文件夹”存放工具函数,调用时与普通函数无异。

                2.5、实例方法 vs classmethod vs staticmethod

                特性
                实例方法
                classmethod
                staticmethod
                第一个参数
                self(实例)
                cls(类)
                能否访问实例属性
                ❌(除非手动给实例)
                能否访问类属性
                ✅(需硬编码类名)
                调用方式
                obj.f()
                Cls.f()obj.f()
                Cls.f()obj.f()
                继承后 cls 动态性
                ——
                ✅ 自动是最派生类
                ❌ 无 cls

                3、属性(Property Members)

                💡
                在 Python 面向对象中,“属性”可以分成两大实现路线:
                1. “定义变量”——最朴素的类属性 / 实例属性;
                1. “基于装饰器”——把方法伪装成属性(@property@staticmethod@classmethod 等)。

                3.1、基于定义变量:类属性 & 实例属性

                • 类属性:所有实例共享;
                • 实例属性:每个对象独立一份;
                • 读写规则:读时“实例→类”,写时“实例新建同名变量”。

                3.2、基于装饰器:把方法“伪装”成属性

                1. @property(只读属性 / 可读写属性)
                    • 访问方式像变量c.area),背后其实是方法调用;
                    • 支持 getter / setter / deleter,实现“数据验证 + 懒加载”。
                1. @staticmethod@classmethod(类级属性伪装)
                    • 静态方法:纯粹工具函数,放在类命名空间内;
                    • 类方法:可读写类变量、充当工厂函数。

                3.3、两条路线的对比速查表

                特性
                定义变量
                @property / @staticmethod / @classmethod
                语法
                attr = value
                @decorator + 函数
                是否可验证
                ✅(getter/setter)
                是否可懒加载
                ✅(计算属性)
                是否可读写类级数据
                类变量可
                类方法可
                调用成本
                方法调用,略高
                • 想“存数据”——用定义变量(类 / 实例属性)
                • 想“数据 + 逻辑封装”——用 @property@staticmethod@classmethod 把方法伪装成属性,实现验证、懒加载、工厂等高级行为。

                3.4、property()方法

                1. 语法
                  1. 作用:把 getter / setter / deleter 三个函数一次性封装成同名属性,实现「数据验证、懒加载、只读/只写」等高级封装,而不暴露内部存储。
                  1. 参数
                    1. 参数
                      默认值
                      描述
                      fget
                      None
                      读属性时调用的函数(getter)
                      fset
                      None
                      写属性时调用的函数(setter)
                      fdel
                      None
                      删除属性时调用的函数(deleter)
                      doc
                      None
                      属性的文档字符串
                  1. 示例

                    3.5、@property@xxx.setter@xxx.deleter 装饰器

                    1. 基本语法(4 种形态)
                      1. 最小完整示例
                        1. 常见用法场景
                          1. 场景
                            典型代码片段
                            惰性计算 / 缓存
                            第一次访问时计算,以后直接返回缓存值
                            校验赋值
                            age 必须在 0~120 之间
                            只读派生属性
                            只提供 getter,不定义 setter
                            动态计算 / 触发事件
                            设置坐标时自动重绘窗口
                            兼容重构
                            把原本公开字段改成方法,但调用方零改动
                        1. 实战进阶示例
                          1. 惰性计算 + 缓存
                            1. 带校验的可写属性
                              1. 兼容重构:把字段换成 property
                              1. 细节与陷阱
                                1. 注意点
                                  说明
                                  优先级别
                                  property数据描述器,实例同名属性会被 覆盖(无法直接赋值),除非实例用 __dict__ 强行绕过。
                                  继承行为
                                  子类可 通过同名函数 + 装饰器 覆盖父 property 的某一部分(只覆盖 setter 等)。
                                  文档字符串
                                  默认继承 getter 方法的 __doc__,可用 @x.getter 重新指定。
                                  通过类调用
                                  Person.full_name 返回 property 自身,可用于 introspection。
                                  性能
                                  每次访问都有一次 Python 级函数调用,对 超热路径 可手动缓存或改用 __slots__ + 描述器优化。

                              📝 面向对象的成员修饰符

                              1、成员修饰符速查表

                              可见级别
                              语法
                              内部/外部访问
                              机制
                              典型场景
                              公开 Public
                              name
                              ✅/✅
                              无限制
                              普通属性/方法
                              受保护 Protected
                              _name
                              ✅/✅(约定)
                              仅 IDE/文档提示
                              子类继承用
                              私有 Private
                              __name
                              ✅/❌(改名)
                              名称重整 _Class__name
                              完全隐藏
                              只读属性
                              @property
                              ✅读/❌写
                              方法伪装属性
                              计算/验证
                              类私有
                              __name__
                              ✅/✅
                              魔术方法
                              系统钩子

                              2、完整示例:

                              3、使用与陷阱演示

                              📝 对象嵌套

                              1、相关概念

                              1.1、一个类的属性 不是普通数字/字符串,而是另一个对象 —— 这就是嵌套。

                              1.2、三种常见套法:

                              套法
                              大白话
                              例子
                              生命周期
                              组合(整体-部分)
                              “我死你随”
                              班级里有学生,班级解散,学生也没了
                              同生同死
                              关联
                              “咱俩认识”
                              学生持有班级引用,但班级可以换
                              可换可空
                              依赖
                              “临时用一下”
                              学生进班级前才 new Classes()
                              用完即弃

                              2、一张图秒懂

                              3、代码对照

                              3.1、 组合(最紧密)

                              3.2、关联(松一点,可换班级)

                              3.3、依赖(最松,临时用)

                              4、生命周期对比表

                              关系
                              对象诞生
                              对象销毁
                              换对象
                              组合
                              整体 __init__ 里一起 new
                              整体销毁,部分一起没
                              不支持
                              关联
                              外部 new 后传进来
                              整体销毁,部分仍活
                              随时换
                              依赖
                              方法里临时 new
                              方法结束即没
                              每次新

                              📝 特殊成员

                              1、__init__,初始化方法

                              1.1、规则一句话

                              子类没定义 __init__ ⇒ 沿 MRO 找第一个定义了 __init__ 的类,把它的实现拿来用;如果这一路谁都没写,最终落到 object.__init__

                              1.2、代码验证

                              1.3、菱形继承再看 MRO

                              MRO: D → B → C → A → object

                              1.4、小结

                              • 子类不写 __init__ ≠ 不执行初始化;
                              • 解释器按 MRO 顺序复用第一个遇到的 __init__
                              • 参数列表必须和“被选中的那个 __init__”完全匹配,否则调用方抛 TypeError
                              • 想“自动转发全部参数”就自己在子类里写 super().__init__(*args, **kwargs)

                              2、__new__,构造方法

                              💡
                              new真正负责“造壳”的构造器,它创建实例并决定返回什么;init 只是给空壳“填肉”的初始化器。

                              2.1、定义与签名

                              2.2、调用顺序

                              2.3、典型用途

                              • 继承不可变类型(int、str、tuple)
                              • 单例模式
                              • 对象池 / 缓存
                              • 元类自定义实例化

                              2.4、示例

                              1. 继承不可变类型
                                1. 单例

                                  2.5、注意

                                  • 必须返回实例;返回 None 或类型不匹配会抛 TypeError
                                  • 仅当返回实例且类型正确时,__init__ 才会被调用。

                                  3、__call__

                                  3.1、作用与语法

                                  实例可以像函数一样被调用——实现 可调用对象(callable instance)

                                  3.2、定义示例

                                  3.3、与函数的区别

                                  • 可携带状态(如上例 count)。
                                  • 可继承、组合、多态,天然面向对象。

                                  3.4、典型场景

                                  • 计数器、缓存器、策略对象、装饰器类。
                                  • 框架钩子(如 torch.nn.Moduleforward 实质由 __call__ 触发)。

                                  3.5、判断与调试

                                  3.6、总结

                                  __call__ 让实例“变身”函数,既能保存状态又能像函数一样使用,是 Python 实现可调用对象的魔法钩子。

                                  4、__str__

                                  4.1、作用与语法

                                  当对象被 print()str() 或 f-string 调用时,Python 自动触发 __str__ 方法,返回面向终端用户的可读字符串

                                  4.2、使用示例

                                  4.3、与 repr 区别

                                  • str:面向用户,简洁、美观。
                                  • repr:面向开发者,通常返回能重建对象的表达式字符串。若只实现 __str__,则 repr(obj) 会回退到默认格式;反之亦然。

                                  4.4、总结

                                  实现 __str__ 让你的对象在打印时直接呈现自定义、友好的文字信息。

                                  5、__dict__

                                  5.1、作用

                                  • 实例字典:保存实例的所有可写属性(不含 slots、描述符、类变量)。
                                  • 类字典:保存类的属性、方法、类变量等。
                                  • 本质是 普通 dict,可动态增删改查。

                                  5.2、语法示例

                                  5.3、常见操作

                                  5.4、注意点

                                  • 使用 __slots__ 的类实例无 __dict__
                                  • 类变量不会出现在实例 __dict__ 中。
                                  • 修改 __dict__立即生效,但破坏封装,慎用于生产代码。

                                  5.5、总结

                                  __dict__ 是实例/类的「属性仓库」,可读写、可遍历,是 Python 动态特性的核心接口之一。

                                  6、__getitem__/__setitem__/__delitem__

                                  💡
                                  这三个魔法方法让自定义对象支持「索引/切片」语法,像列表、字典一样用 obj[key]obj[key] = valuedel obj[key]

                                  6.1、方法签名

                                  6.2、最小可运行示例(列表包装器)

                                  6.3、切片也走同一路径

                                  • obj[1:3] 等价于 obj.__getitem__(slice(1, 3, None))
                                  • obj[1:3] = [4,5] 等价于 obj.__setitem__(slice(1,3), [4,5])

                                  6.4、常见陷阱

                                  场景
                                  说明
                                  KeyError / IndexError
                                  自己决定抛什么异常;Python 规范期望 KeyError 用于 dict-like,IndexError 用于 list-like
                                  只读容器
                                  不实现 setitemdelitem 即可
                                  不可切片的键
                                  getitem 里手动判断 isinstance(key, slice)

                                  6.5、总结

                                  实现 __getitem__/__setitem__/__delitem__ 就能把自定义对象变成「可索引、可赋值、可删除」的容器,语法与内置容器完全一致。

                                  7、__enter__/__exit__

                                  💡
                                  实现这两个方法后,实例就能与 with 语句配合,自动完成资源获取与清理,形成上下文管理器(Context Manager)。

                                  7.1、协议规则

                                  方法
                                  触发时机
                                  返回值
                                  异常处理
                                  enter(self)
                                  with 代码块开始时
                                  任意对象(赋给 as 变量)
                                  exit(self, exc_type, exc_val, exc_tb)
                                  with 代码块结束时(无论正常或异常)
                                  True 吞掉异常,False 继续传播
                                  接收异常三元组

                                  7.2、最小可运行示例

                                  运行输出

                                  7.3、异常处理示例

                                  7.4、总结

                                  实现 __enter__/__exit__,你的对象就能被 with 托管,自动完成“资源获取—使用—释放”三步曲,异常也能优雅收尾。

                                  8、__add__

                                  8.1、作用

                                  当对象出现在 + 左侧时,解释器自动调用 obj.__add__(other),返回“加法”结果;若未实现,则尝试调用 other.__radd__(obj)

                                  8.2、签名

                                  8.3、完整示例

                                  8.4、类型检查

                                  8.5、总结

                                  重写 __add__ 即可让自定义对象支持 + 运算符,实现“向量、金额、矩阵”等加法语义。

                                  9、__iter__

                                  9.1、作用

                                  使自定义对象可迭代for ... in obj:list(obj) 等)。
                                  解释器在需要迭代时,先调用 iter(obj)obj.__iter__(),该方法必须返回迭代器(即实现了 __next__ 的对象)。

                                  9.2、最小实现

                                  9.3、快捷写法:让对象自己就是迭代器

                                  9.4、总结

                                  只要类提供 __iter__ 并返回一个带 __next__ 的迭代器,就能让实例直接用于 for 循环、推导式、解包等所有迭代场景。

                                  📝 魔术方法(Magic / Special Methods)速查表

                                  1、对象生命周期

                                  方法
                                  触发时机
                                  典型用途
                                  __new__(cls, ...)
                                  构建空实例
                                  单例、不可变类型扩展
                                  __init__(self, ...)
                                  填充初始状态
                                  常规初始化
                                  __del__(self)
                                  实例将被回收
                                  释放非内存资源(文件、句柄)

                                  2、运算符重载

                                  类别
                                  方法
                                  表达式
                                  比较
                                  __eq__, __ne__, __lt__, __le__, __gt__, __ge__
                                  a == b, a < b ...
                                  算术
                                  __add__, __sub__, __mul__, __truediv__, __floordiv__, __mod__, __pow__
                                  a + b, a - b ...
                                  位运算
                                  __and__, __or__, __xor__, __lshift__, __rshift__
                                  a & b, a \| b ...
                                  反向/就地
                                  __radd__, __iadd__ ...
                                  1 + obj, obj += 1
                                  一元
                                  __neg__, __pos__, __invert__
                                  -obj, ~obj

                                  3、容器协议(列表/字典/集合行为)

                                  方法
                                  表达式/作用
                                  备注
                                  __len__
                                  len(obj)
                                  长度
                                  __getitem__(self, key)
                                  obj[key]
                                  支持切片 slice
                                  __setitem__(self, key, val)
                                  obj[key] = val
                                  __delitem__(self, key)
                                  del obj[key]
                                  __contains__(self, item)
                                  item in obj
                                  成员测试
                                  __iter__(self)
                                  for i in obj
                                  迭代器协议
                                  __reversed__(self)
                                  reversed(obj)
                                  反向迭代

                                  4、可调用对象

                                  方法
                                  表达式
                                  说明
                                  __call__(self, *args, **kw)
                                  obj(*args, **kw)
                                  让实例像函数一样使用

                                  5、上下文管理器(with 语句)

                                  方法
                                  表达式
                                  说明
                                  __enter__(self)
                                  with obj as x:
                                  进入上下文
                                  __exit__(self, exc_type, exc_val, exc_tb)
                                  离开 with
                                  清理资源、异常抑制

                                  6、字符串/字节表示

                                  方法
                                  表达式
                                  说明
                                  __str__(self)
                                  str(obj) / print(obj)
                                  用户友好字符串
                                  __repr__(self)
                                  repr(obj) / 调试台
                                  开发者字符串,力求 eval(repr(obj))==obj
                                  __format__(self, fmt)
                                  f"{obj:fmt}"
                                  自定义格式化
                                  __bytes__(self)
                                  bytes(obj)
                                  字节序列

                                  7、描述符协议(@property 底层)

                                  方法
                                  触发
                                  说明
                                  __get__(self, obj, owner)
                                  读取属性
                                  实现 property、缓存等
                                  __set__(self, obj, val)
                                  设置属性
                                  可写描述符
                                  __delete__(self, obj)
                                  删除属性
                                  可删除描述符

                                  8、异步协议

                                  方法
                                  表达式
                                  说明
                                  __await__
                                  await obj
                                  awaitable 对象
                                  __aiter__, __anext__
                                  async for
                                  异步迭代器
                                  __aenter__, __aexit__
                                  async with
                                  异步上下文

                                  9、复制与序列化

                                  方法
                                  表达式
                                  说明
                                  __copy__, __deepcopy__
                                  copy.copy(obj) / copy.deepcopy(obj)
                                  浅/深拷贝
                                  __reduce__, __reduce_ex__
                                  pickle.dumps(obj)
                                  pickle 序列化钩子

                                  10、抽象基类钩子(部分)

                                  方法
                                  说明
                                  __subclasshook__
                                  issubclass 自定义判断
                                  __instancecheck__
                                  isinstance 自定义判断
                                2. PythonObject
                                3. Python面向对象-面向对象基础Python面向对象-面向对象高级和应用
                                  Loading...
                                  Catalog
                                  0%