Python
基础语法
01概念
02安装
03变量
04字符串
05数
06常量与注释
07列表
08元组
09if语句
10字典
11集合
12复合数据类型对比
13推导式
14用户输入
15while循环
16函数
17类
18面向对象编程
19文件操作
20异常处理
21日期和时间
22魔术方法
23内置函数
24线程
25并发&并行
26正则表达式
27迭代器
28装饰器
29生成器
30上下文管理器
31函数式编程
32闭包
33解包
34工具库
35连接关系型数据库
36虚拟环境
37异步编程
网络爬虫
01urllib库[了解]
02requests库
03数据交换格式
04解析库
05lxml
06Beautiful Soup
07Xpath语法
08动态网页的处理
-
+
首页
22魔术方法
Python 中的**魔术方法**(Magic Methods)是一类以双下划线 \_\_ 开头和结尾的特殊方法,由解释器在特定场景下自动调用,用于定义类的实例在不同操作中的行为(如初始化、运算、属性访问等)。它们是实现 Python 面向对象特性的核心机制,让自定义类能像内置类型(如列表、字典)一样自然交互。 ## \_\_name\_\_ \_\_name\_\_ 是 Python 中每个模块(.py 文件)都有的内置特殊变量,其值取决于模块的使用方式: - 当模块**直接被运行**时(如 python script.py),\_\_name\_\_ 的值为 "\_\_main\_\_"; - 当模块**被导入到其他模块**时(如 import script),\_\_name\_\_ 的值为模块名(即 script)。 **if \_\_name\_\_ == "\_\_main\_\_": 的作用** 这一判断的核心目的是:**让模块中的部分代码仅在模块直接运行时执行,而在被导入时不执行**。这相当于为模块定义了 “主程序模式” 下的逻辑,类似其他语言的 main 方法功能。 例如: 直接运行 ```python # 模块文件:my\_module.py def add(a, b): return a + b # 以下代码仅在模块直接运行时执行 if __name__ == "__main__": print("模块被直接运行") result = add(2, 3) print(f"2 + 3 = {result}") #输出 #模块被直接运行 #2 + 3 = 5 ``` 作为模块导入 ```python import my_module # 导入模块,此时 my_module.__name__ = "my_module" print(my_module.add(2, 3)) # 输出:5(仅调用函数,不执行 if 内的代码) ``` 与类的魔术方法的区别: **所属范畴不同**: - if \_\_name\_\_ == "\_\_main\_\_": 是**模块级别的逻辑**,用于控制整个脚本的执行入口,与类无关; - 魔术方法(如 \_\_init\_\_、\_\_add\_\_)是**类的特殊方法**,用于定义类实例的行为,属于面向对象特性。 **触发方式不同**: - if \_\_name\_\_ == "\_\_main\_\_": 中的代码仅在模块直接运行时执行,由 Python 解释器根据 \_\_name\_\_ 变量的值判断; - 魔术方法由特定操作(如实例化、运算、属性访问)自动触发,与模块是否直接运行无关。 ## 生命周期管理 方法用于定义实例从创建到销毁的完整生命周期,是类最基础的魔术方法。 | 方法名 | 作用 | 触发时机 | 示例场景 | | ----------------------------------- | -------------------------------------------- | -------------------------------------------------------- | ------------------------------------------ | | \_\_new\_\_(cls, *args, **kwargs) | 创建并返回类的实例(唯一返回实例的魔术方法) | 调用类创建实例时(cls(*args)),在 \_\_init\_\_ 之前执行 | 实现单例模式(确保类只有一个实例) | | \_\_init\_\_(self, *args, **kwargs) | 初始化实例(为实例绑定属性) | 实例创建后自动调用(\_\_new\_\_ 之后) | 定义实例的初始状态(如 Person(name, age)) | | \_\_del\_\_(self) | 定义实例被销毁时的行为(垃圾回收) | 实例引用计数为 0 时(被垃圾回收) | 释放资源(如关闭文件、数据库连接) | 例如: ```python class Singleton: _instance = None # 存储唯一实例 def __new__(cls, *args, **kwargs): if cls._instance is None: # 调用父类方法创建实例 cls._instance = super().__new__(cls) return cls._instance # 返回唯一实例 # 测试:两次创建的实例是同一个对象 a = Singleton() b = Singleton() print(a is b) # 输出:True ``` ## 字符串表示 这类方法控制实例在转换为字符串时的输出,影响 print()、str()、repr() 等操作的结果。 | 方法名 | 作用 | 触发时机 | 核心区别 | | -------------------------- | ---------------------------------------- | -------------------------------------- | ---------------------------------- | | \_\_str\_\_(self) | 返回**用户友好**的字符串(可读性优先) | str(obj) 或 print(obj) 时 | 面向用户,简洁易读 | | \_\_repr\_\_(self) | 返回**开发者友好**的字符串(精确性优先) | repr(obj) 或交互式环境中直接输入实例时 | 面向开发,可用于重建实例 | | \_\_format\_\_(self, spec) | 定义格式化字符串规则 | format(obj, spec) 时 | 支持自定义格式化(如 f"{obj:xx}") | **示例:\_\_str\_\_ 与 \_\_repr\_\_ 的区别** ```python class Book: def __init__(self, title, author): self.title = title self.author = author def __str__(self): return f"《{self.title}》({self.author})" # 用户视角 def __repr__(self): return f"Book(title='{self.title}', author='{self.author}')" # 开发者视角 b = Book("Python编程", "张三") print(str(b)) # 输出:《Python编程》(张三) print(repr(b)) # 输出:Book(title='Python编程', author='张三') ``` ## 运算符重载 通过重写这些方法,可让自定义类的实例支持 +、-、==、[] 等运算符,实现自定义运算逻辑。 **1. 算术运算符** | 方法名 | 对应运算符 | 作用 | | ----------------------------- | ------------- | ------ | | \_\_add\_\_(self, other) | self + other | 加法 | | \_\_sub\_\_(self, other) | self - other | 减法 | | \_\_mul\_\_(self, other) | self * other | 乘法 | | \_\_truediv\_\_(self, other) | self / other | 真除法 | | \_\_floordiv\_\_(self, other) | self // other | 地板除 | **2. 比较运算符** | 方法名 | 对应运算符 | 作用 | | ----------------------- | ------------- | ----------------------------- | | \_\_eq\_\_(self, other) | self == other | 等于 | | \_\_ne\_\_(self, other) | self != other | 不等于(默认 not \_\_eq\_\_) | | \_\_lt\_\_(self, other) | self < other | 小于 | | \_\_gt\_\_(self, other) | self > other | 大于 | ```python class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) raise TypeError("只能与 Vector 实例相加") v1 = Vector(1, 2) v2 = Vector(3, 4) print((v1 + v2).x) # 输出:4(v1 + v2 结果为 Vector(4, 6)) ``` ## 属性访问 这类方法用于拦截属性的访问、赋值、删除等操作,实现属性的精细化控制(如权限校验、动态生成)。 | 方法名 | 作用 | 触发时机 | 注意事项 | | ---------------------------------- | ------------------------------------ | ------------------------- | ----------------------------------------------------------- | | \_\_getattr\_\_(self, name) | 访问**不存在的属性**时调用 | obj.name 且 name 不存在时 | 仅针对不存在的属性 | | \_\_setattr\_\_(self, name, value) | 拦截所有属性的赋值 | obj.name = value 时 | 直接赋值 self.name 会触发递归,需用 super().\_\_setattr\_\_ | | \_\_delattr\_\_(self, name) | 拦截属性的删除 | del obj.name 时 | 慎用,避免误删关键属性 | | \_\_getattribute\_\_(self, name) | 拦截**所有属性的访问**(包括存在的) | 任何 obj.name 操作时 | 优先级高于 \_\_getattr\_\_,易引发递归 | **示例:动态属性(\_\_getattr\_\_)** ```python class User: def __init__(self, info): self.info = info # info 是字典,如 {"name": "Alice", "age": 20} # 访问不存在的属性时,尝试从 info 中获取 def __getattr__(self, name): if name in self.info: return self.info[name] raise AttributeError(f"属性 '{name}' 不存在") u = User({"name": "Alice", "age": 20}) print(u.name) # 输出:Alice(自动从 info 中获取) print(u.gender) # 报错:AttributeError ``` ## 容器行为 通过实现这些方法,可让实例支持类似容器的操作(如索引、长度、迭代)。 | 方法名 | 作用 | 触发时机 | 对应内置类型行为 | | --------------------------------- | ---------------------- | ------------------- | -------------------------------- | | \_\_len\_\_(self) | 返回容器长度 | len(obj) 时 | 列表 / 字典的 len() | | \_\_getitem\_\_(self, key) | 获取 key 对应的值 | obj[key] 或切片时 | 列表 lst[i]、字典 dct[k] | | \_\_setitem\_\_(self, key, value) | 设置 key 对应的值 | obj[key] = value 时 | 列表 lst[i] = v、字典 dct[k] = v | | \_\_iter\_\_(self) | 返回迭代器 | for x in obj 时 | 列表 / 字典的迭代 | | \_\_contains\_\_(self, item) | 判断 item 是否在容器中 | item in obj 时 | x in lst、x in dct | **示例:自定义列表(\_\_len\_\_ + \_\_getitem\_\_)** ```python class MyList: def __init__(self, data): self.data = data def __len__(self): return len(self.data) def __getitem__(self, index): return self.data[index] ml = MyList([10, 20, 30]) print(len(ml)) # 输出:3(调用 __len__) print(ml[1]) # 输出:20(调用 __getitem__) ``` ## 调用行为与上下文管理 这两类方法用于扩展实例的交互能力,支持函数式调用和 with 语句。 | 方法名 | 作用 | 触发时机 | 典型应用 | | ------------------------------------------------ | ---------------------- | -------------------- | ---------------------------------- | | \_\_call\_\_(self, *args) | 让实例像函数一样被调用 | obj(*args) 时 | 实现可调用对象(如计数器、装饰器) | | \_\_enter\_\_(self) | 进入 with 块时获取资源 | with obj: ... 进入前 | 自动获取资源(如打开文件) | | \_\_exit\_\_(self, exc\_type, exc\_val, exc\_tb) | 退出 with 块时释放资源 | with obj: ... 退出时 | 自动释放资源(如关闭文件) | **示例 1:可调用实例(\_\_call\_\_)** ```python class Counter: def __init__(self): self.count = 0 def __call__(self): self.count += 1 return self.count c = Counter() print(c()) # 输出:1(第一次调用) print(c()) # 输出:2(第二次调用) ``` **示例 2:上下文管理(\_\_enter\_\_ + \_\_exit\_\_)** ```python class FileHandler: def __init__(self, path, mode): self.path = path self.mode = mode self.file = None def __enter__(self): self.file = open(self.path, self.mode) return self.file # 赋值给 with 语句的变量 def __exit__(self, *args): if self.file: self.file.close() # 自动关闭文件 # 自动打开和关闭文件 with FileHandler("test.txt", "w") as f: f.write("Hello") ``` ## 其他常用魔术方法 | 方法名 | 作用 | 触发时机 | | -------------------- | -------------------------- | ------------------------ | | \_\_bool\_\_(self) | 定义实例的布尔值 | bool(obj) 或 if obj: 时 | | \_\_hash\_\_(self) | 返回实例的哈希值 | hash(obj) 或作为字典键时 | | \_\_sizeof\_\_(self) | 返回实例的内存大小(字节) | sys.getsizeof(obj) 时 | **示例:自定义布尔值(\_\_bool\_\_)** ```python class EmptyList: def __init__(self, data): self.data = data def __bool__(self): return len(self.data) > 0 # 数据为空时返回 False el1 = EmptyList([1, 2]) el2 = EmptyList([]) print(bool(el1)) # 输出:True print(bool(el2)) # 输出:False ``` ## 总结 魔术方法是 Python 面向对象的 “灵魂”,其核心价值是让自定义类能够: - 像内置类型一样响应运算符、print、len 等操作; - 实现自动资源管理、动态属性、容器行为等高级特性; - 让代码更简洁、更符合 Python 风格(Pythonic)。
毛林
2025年9月7日 12:01
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码