类与对象(Class & Object)

一. 面向对象与类的基础

类(Class)是封装对象属性和行为的载体,具有相同属性和行为的一类实体被称为类。

==在 Python 中“一切皆对象”,每个对象都有其独立的身份(id() 返回内存地址)、类型(type())和值(内容)。==对象与类的关系,即具体实例与抽象类型之间的关系。

二. 访问权限与成员保护

Python 并没有 C++ 那种强制性的 publicprivate 关键字,它通过 命名规范 来约定访问权限。

1. 公有成员(Public)

特征: 无前置下划线(如 name, func())。
权限: 类内部、子类内部以及外部均可自由访问。

2. 受保护成员(Protected)

特征: 单下划线开头(如 _age, _func())。
权限: 虽然技术上在外部仍能访问,但 Python 约定这属于内部属性,不建议外部直接调用。

3. 私有成员(Private)

对应 C++: private
特征: 双下划线开头,且无结尾下划线(如 __id, __func())。
权限: 仅限类内部访问。Python 会对其进行“名称修饰”,外部无法直接通过原名访问;但继承的类也可以通过self.__xx访问,但不能直接访问。

4. 特殊方法/魔法方法(Dunder Methods)

特征: 开头和结尾都有双下划线(如 __init__, __str__)。
注意: 它们是系统预留的特殊接口,及:公有的;但系统自动调用,不会手动调用。

(1).对象创建/初始化
方法 触发时机
__new__ 创建对象时(较少直接用)
__init__ 初始化对象时自动调用
(2).字符串/输出
方法 触发时机
__str__ print(obj) 时调用(给用户看)
__repr__ repr(obj) / 调试时调用(给开发者看)
(3).容器相关
方法 触发时机
__len__ len(obj)
__getitem__ obj[key]
__setitem__ obj[key] = value
__delitem__ del obj[key]
__iter__ for 循环遍历
__contains__ item in obj
(4).运算符重载
方法 触发时机
__add__ +
__sub__ -
__mul__ *
__truediv__ /
__eq__ ==
__lt__ <
(5).类型转换
方法 触发时机
__int__ int(obj)
__float__ float(obj)
__str__ str(obj)
__bool__ bool(obj)
(6).属性访问
方法 触发时机
__getattr__ 访问不存在属性
__setattr__ 设置属性
__delattr__ 删除属性
(7).可调用对象
方法 触发时机
__call__ 对象像函数一样调用
(8).上下文管理
方法 触发时机
__enter__ with 进入
__exit__ with 结束

三. 成员变量 (数据成员)

在 Python 中,成员变量根据其作用域和初始化时机分为 类属性(静态成员变量)实例属性(普通成员变量)

1. 类属性 (静态成员变量)

作用: 属于类本身,被该类的所有对象共享。在内存中只存在一份,类似于 C++ 的 static 成员。

  • 初始化时机: 类定义时立即初始化(在代码执行到 class 语句块时)。
  • 如何初始化: 直接在类体中、函数体外进行赋值。
  • 访问方式: 推荐使用 类名.属性名 访问,也可以通过 实例.属性名 访问。
class Human:
    mam = True  # 公有类属性(静态成员)
    _category = "Mammal"  # 受保护类属性
    __logic_gate = True  # 私有类属性

2. 实例属性 (普通成员变量)

作用: 属于具体的对象实例。每个对象都拥有一份独立的拷贝,互不影响。

  • 初始化时机: 实例化对象时初始化。
  • 如何初始化: 通常在构造函数 __init__ 中,通过 self.属性名 = 值 进行赋值。
class Human:
    def __init__(self, name, secret):
        self.name = name  # 公有实例属性
        self.__secret = secret  # 私有实例属性:外部无法直接通过 zs.__secret 访问

四. 成员函数 (方法)

1. 实例方法 (普通成员函数)

作用: 最常用的方法。可以访问实例属性和类属性。

  • 格式: 第一个参数必须是 self(代表当前对象实例)。
  • 私有化: 若方法名以 __ 开头,则变为私有方法,外部不可见;继承的子类可以通过self.xx访问,但不能直接访问

2. 类方法 (Class Method)

作用: 类似于 C++ 的静态成员函数,但它能感知到类本身。

  • 格式: 使用 @classmethod 装饰,第一个参数必须是 cls(代表类本身)。

3. 静态方法 (Static Method)

作用: 纯粹的工具函数。既不访问 self 也不访问 cls

  • 格式: 使用 @staticmethod 装饰。

五. 构造函数与初始化细节

1. __init__ - 构造函数

作用: 在类被实例化创建对象时由系统自动调用,用于执行“普通成员变量”的初始化。

参数说明:

  • self (实例本身):类似于 C++ 中的 this 指针。
    • 自动传入: 调用时不需要手动传递,Python 会自动将当前创建的对象绑定到 self 上。
    • 必须存在: 必须作为所有实例方法的第一个参数。

返回值:

  • NoneType: 构造函数不能有返回值(固定返回 None)。

六. 封装、继承与高级应用

1. @property - 属性封装

作用: 将一个方法伪装成“成员变量”。常用于实现只读变量或对私有变量进行受控读取。

class Human:
    def __init__(self, secret):
        self.__secret = secret # 私有变量

    @property
    def secret(self):
        # 外部可以通过 zs.secret 读取,但无法直接修改
        return self.__secret

2. 类的继承

作用: 子类完全继承父类的所有公有和受保护属性和方法。子类可以重写(Override)父类的方法。

  • 注意: 子类不能直接访问父类的私有成员 (__xx),但可以通过self.__xx访问。

3. 子类显式调用父类构造函数

作用: 在 Python 中,如果子类定义了自己的 __init__ 方法,父类的 __init__ 不会被自动调用。若需在子类中使用父类的初始化逻辑,必须显式调用。

(1). 使用super()调用
  • 语法: super().__init__(参数)
  • 特点: 不需要显式提供父类名称,自动遵循 MRO(方法解析顺序),是多重继承下的最佳实践。
(2). 使用父类名显式调用
  • 语法: 父类名.__init__(self, 参数)
  • 特点: 必须手动传入 self 实例。

示例代码:

class Student(Human):
    def __init__(self, name, secret, school):
        # 方式 1:使用 super() (推荐)
        super().__init__(name, secret) 
        
        # 方式 2:使用父类名调用
        # Human.__init__(self, name, secret)
        
        self.school = school  # 初始化子类特有属性

4. isinstance - 类型检查

作用: 判断一个对象是否属于某个类或其子类。

5. 动态多维扩展 (*args)

作用: 利用可变长参数接收任意数量的参数。

class PointND:
    def __init__(self, *args):
        self.__coords = list(args) # 将坐标封装为私有列表
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐