前言
在 python 中,魔术方法(magic methods) 是一组以双下划线 __ 开头和结尾的特殊方法(如 __init__、__str__),用于实现类的核心行为(如构造、运算、比较、属性访问等)。它们由 python 解释器自动调用,无需开发者显式触发,是实现面向对象高级特性(如迭代器、上下文管理器、运算符重载)的核心工具。
以下是 python 中全部核心魔术方法的分类整理,涵盖初始化、属性访问、运算重载、容器行为、迭代器、上下文管理等场景,并附带功能说明和典型示例,帮助你系统理解其用法。
一、初始化与销毁:对象的创建与回收
这类方法控制对象的创建、初始化和销毁过程,是类最基础的魔术方法。
| 魔术方法 | 功能说明 | 示例代码 |
|---|---|---|
__new__(cls, *args, **kwargs) | 创建对象:在 __init__ 之前调用,返回类的实例(负责内存分配),常用于不可变类型(如 int、str)的定制。 | python class singleton: _instance = none def __new__(cls): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance s1 = singleton() s2 = singleton() print(s1 is s2) # true(单例模式) |
__init__(self, *args, **kwargs) | 初始化对象:对象创建后调用,用于初始化实例属性(无返回值),是最常用的魔术方法。 | python class person: def __init__(self, name, age): self.name = name self.age = age p = person("alice", 25) print(p.name) # alice |
__del__(self) | 销毁对象:对象被垃圾回收时调用(时机不确定,不建议依赖),用于释放资源(如文件句柄)。 | python class filehandler: def __init__(self, path): self.file = open(path, "w") def __del__(self): self.file.close() # 回收时关闭文件 |
二、属性访问:控制实例属性的读写
这类方法用于定制实例属性的访问、赋值、删除逻辑,实现属性的封装、校验或动态计算(如@property 的底层原理)。
| 魔术方法 | 功能说明 | 示例代码 |
|---|---|---|
__getattr__(self, name) | 当访问不存在的实例属性时调用,返回属性值或抛出 attributeerror。 | python class dynamicattr: def __getattr__(self, name): if name == "full_name": return f"{self.first_name} {self.last_name}" raise attributeerror(f"no attribute {name}") d = dynamicattr() d.first_name = "bob" d.last_name = "smith" print(d.full_name) # bob smith |
__setattr__(self, name, value) | 当给实例属性赋值时调用(包括存在和不存在的属性),可用于属性校验。 | python class person: def __setattr__(self, name, value): if name == "age" and (not isinstance(value, int) or value < 0): raise valueerror("age must be a non-negative integer") super().__setattr__(name, value) # 必须调用父类方法,避免递归 p = person() p.age = 25 # 正常 p.age = -5 # 抛出 valueerror |
__delattr__(self, name) | 当删除实例属性(del obj.name)时调用,可用于限制属性删除。 | python class protectedattr: def __delattr__(self, name): if name == "id": raise permissionerror("cannot delete 'id' attribute") super().__delattr__(name) p = protectedattr() p.id = 123 del p.id # 抛出 permissionerror |
__getattribute__(self, name) | 访问任何实例属性时都会优先调用(包括存在的属性),需谨慎使用(避免递归),常用于全局属性控制。 | python class logattr: def __getattribute__(self, name): print(f"accessing attribute: {name}") return super().__getattribute__(name) # 必须调用父类,避免递归 l = logattr() l.x = 10 print(l.x) # 先打印 "accessing attribute: x",再输出 10 |
三、字符串表示:定制对象的打印与转换
这类方法控制对象在字符串场景下的表现(如 print(obj)、str(obj)、repr(obj)),帮助调试和用户友好展示。
| 魔术方法 | 功能说明 | 示例代码 |
|---|---|---|
__str__(self) | 当调用 str(obj) 或 print(obj) 时调用,返回用户友好的字符串(可读性优先)。 | python class person: def __init__(self, name): self.name = name def __str__(self): return f"person(name='{self.name}')" p = person("alice") print(p) # 输出 person(name='alice') |
__repr__(self) | 当调用 repr(obj) 或在交互式环境中直接输入对象时调用,返回开发者友好的字符串(用于还原对象,唯一性优先)。 | python class person: def __init__(self, name): self.name = name def __repr__(self): return f"person('{self.name}')" p = person("bob") print(repr(p)) # 输出 person('bob') (可直接用于创建对象) |
__format__(self, format_spec) | 当调用 format(obj, format_spec) 或使用 f-string 格式化时调用,定制格式化逻辑。 | python class time: def __init__(self, h, m): self.h = h self.m = m def __format__(self, spec): if spec == "24h": return f"{self.h:02d}:{self.m:02d}" elif spec == "12h": period = "am" if self.h < 12 else "pm" return f"{self.h%12:02d}:{self.m:02d} {period}" t = time(15, 30) print(f"24h: {t:24h}") # 24h: 15:30 print(f"12h: {t:12h}") # 12h: 03:30 pm |
__bytes__(self) | 当调用 bytes(obj) 时调用,返回对象的字节表示(bytes 类型)。 | python class text: def __init__(self, content): self.content = content def __bytes__(self): return self.content.encode("utf-8") t = text("hello") print(bytes(t)) # b'hello' |
四、运算符重载:让对象支持算术/比较运算
这类方法允许自定义类的实例支持 python 内置运算符(如 +、>、==),是实现“对象运算”的核心。
4.1 算术运算符(+、-、*、/ 等)
| 魔术方法 | 对应运算符 | 功能说明 | 示例(以 __add__ 为例) |
|---|---|---|---|
__add__(self, other) | + | 加法(self + other) | python class vector: def __init__(self, x): self.x = x def __add__(self, other): return vector(self.x + other.x) v1 = vector(2) v2 = vector(3) print((v1 + v2).x) # 5 |
__sub__(self, other) | - | 减法(self - other) | - |
__mul__(self, other) | * | 乘法(self * other) | - |
__truediv__(self, other) | / | 真除法(self / other) | - |
__floordiv__(self, other) | // | 地板除法(self // other) | - |
__mod__(self, other) | % | 取模(self % other) | - |
__pow__(self, other) | ** | 幂运算(self ** other) | - |
注:反向算术运算符(如
other + self,当other不支持与self运算时调用):__radd__、__rsub__、__rmul__等,用法与正向类似。
4.2 比较运算符(==、>、< 等)
| 魔术方法 | 对应运算符 | 功能说明 | 示例(以 __eq__ 和 __gt__ 为例) |
|---|---|---|---|
__eq__(self, other) | == | 等于(self == other) | python class person: def __init__(self, id): self.id = id def __eq__(self, other): return self.id == other.id p1 = person(1) p2 = person(1) print(p1 == p2) # true |
__ne__(self, other) | != | 不等于(self != other) | (若未定义,默认返回 not __eq__ 的结果) |
__gt__(self, other) | > | 大于(self > other) | python class number: def __init__(self, n): self.n = n def __gt__(self, other): return self.n > other.n num1 = number(5) num2 = number(3) print(num1 > num2) # true |
__ge__(self, other) | >= | 大于等于 | - |
__lt__(self, other) | < | 小于 | - |
__le__(self, other) | <= | 小于等于 | - |
4.3 赋值运算符(+=、-=、*= 等)
| 魔术方法 | 对应运算符 | 功能说明 | 示例(以 __iadd__ 为例) |
|---|---|---|---|
__iadd__(self, other) | += | 增量加法(self += other) | python class counter: def __init__(self, num): self.num = num def __iadd__(self, other): self.num += other return self c = counter(10) c += 5 print(c.num) # 15 |
__isub__(self, other) | -= | 增量减法 | - |
__imul__(self, other) | *= | 增量乘法 | - |
__itruediv__(self, other) | /= | 增量真除法 | - |
4.4 位运算符(&、|、^、<<、>> 等)
| 魔术方法 | 对应运算符 | 功能说明 |
|---|---|---|
__and__(self, other) | & | 按位与 |
__or__(self, other) | ` | ` |
__xor__(self, other) | ^ | 按位异或 |
__lshift__(self, other) | << | 左移 |
__rshift__(self, other) | >> | 右移 |
五、容器行为:让对象像列表/字典一样工作
这类方法允许自定义类的实例支持容器操作(如 len(obj)、obj[key]、for item in obj),实现类似列表、字典的行为。
| 魔术方法 | 对应操作 | 功能说明 | 示例(实现一个简单列表) |
|---|---|---|---|
__len__(self) | len(obj) | 返回容器的元素个数(必须返回整数)。 | python class mylist: def __init__(self, data): self.data = data def __len__(self): return len(self.data) ml = mylist([1,2,3]) print(len(ml)) # 3 |
__getitem__(self, key) | obj[key] | 获取容器中 key 对应的元素(支持索引、切片),无对应 key 时抛 keyerror。 | python class mylist: def __init__(self, data): self.data = data def __getitem__(self, key): return self.data[key] ml = mylist([1,2,3]) print(ml[1]) # 2 print(ml[1:]) # [2,3] |
__setitem__(self, key, value) | obj[key] = value | 给容器中 key 对应的元素赋值,无对应 key 时可新增。 | python class mylist: def __init__(self, data): self.data = data def __setitem__(self, key, value): self.data[key] = value ml = mylist([1,2,3]) ml[1] = 10 print(ml.data) # [1,10,3] |
__delitem__(self, key) | del obj[key] | 删除容器中 key 对应的元素,无对应 key 时抛 keyerror。 | python class mylist: def __init__(self, data): self.data = data def __delitem__(self, key): del self.data[key] ml = mylist([1,2,3]) del ml[1] print(ml.data) # [1,3] |
__contains__(self, item) | item in obj / item not in obj | 判断 item 是否在容器中,返回布尔值(未定义则默认遍历判断)。 | python class mylist: def __init__(self, data): self.data = data def __contains__(self, item): return item in self.data ml = mylist([1,2,3]) print(2 in ml) # true print(4 in ml) # false |
__iter__(self) | for item in obj | 返回一个迭代器(用于遍历容器),通常与 yield 配合或返回 iter(self.data)。 | python class mylist: def __init__(self, data): self.data = data def __iter__(self): for item in self.data: yield item # 生成迭代器 ml = mylist([1,2,3]) for num in ml: print(num) # 1, 2, 3 |
__reversed__(self) | reversed(obj) | 返回容器的反向迭代器(用于 reversed(obj))。 | python class mylist: def __init__(self, data): self.data = data def __reversed__(self): return reversed(self.data) ml = mylist([1,2,3]) print(list(reversed(ml))) # [3,2,1] |
六、迭代器与生成器:控制迭代过程
迭代器的核心是 __iter__ 和 __next__ 方法,生成器则是通过 yield 简化迭代器实现,但魔术方法仍可定制生成器行为。
| 魔术方法 | 功能说明 | 示例(实现一个自定义迭代器) |
|---|---|---|
__iter__(self) | 返回迭代器对象本身(必须实现,用于 for 循环)。 | python class counter: def __init__(self, max_num): self.max = max_num self.current = 0 def __iter__(self): return self # 返回自身作为迭代器 def __next__(self): if self.current < self.max: self.current += 1 return self.current else: raise stopiteration # 迭代结束 c = counter(3) for num in c: print(num) # 1, 2, 3 |
__next__(self) | 返回下一个迭代元素,无元素时抛 stopiteration(迭代器核心)。 | - |
__send__(self, value) | 向生成器发送值(用于 yield 表达式接收外部值),生成器专用。 | python def generator(): while true: x = yield # 接收外部发送的值 print(f"received: {x}") g = generator() next(g) # 启动生成器 g.send(10) # 输出 "received: 10" g.send(20) # 输出 "received: 20" |
__close__(self) | 关闭生成器(调用后生成器无法再生成值,抛 generatorexit)。 | python def generator(): yield 1 yield 2 g = generator() print(next(g)) # 1 g.close() next(g) # 抛 stopiteration |
七、上下文管理:实现with语句支持
通过 __enter__ 和 __exit__ 方法,让对象支持 with 语句(自动管理资源,如文件关闭、锁释放)。
| 魔术方法 | 功能说明 | 示例(实现一个自定义文件管理器) |
|---|---|---|
__enter__(self) | 进入 with 块时调用,返回的对象可赋值给 as 后的变量(如 with open(...) as f)。 | python class myfile: def __init__(self, path, mode): self.path = path self.mode = mode def __enter__(self): self.file = open(self.path, self.mode) return self.file # 赋值给 as 后的变量 def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() # 退出 with 块时自动关闭 # 使用 with myfile("test.txt", "w") as f: f.write("hello") # 文件已自动关闭 |
__exit__(self, exc_type, exc_val, exc_tb) | 退出 with 块时调用,处理异常(若有):- exc_type:异常类型(无异常则为 none)- exc_val:异常实例- exc_tb:异常追踪栈返回 true 表示异常已处理,不向外传播。 | python class safefile: def __init__(self, path): self.path = path def __enter__(self): self.file = open(self.path, "w") return self.file def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() if exc_type is not none: print(f"error: {exc_val}") return true # 处理异常,不向外传播 # 测试异常 with safefile("test.txt") as f: f.write(123) # 抛出 typeerror # 输出 "error: write() argument must be str, not int",无崩溃 |
八、其他常用魔术方法
8.1 可调用对象:让实例像函数一样调用
通过 __call__ 方法,让类的实例支持函数调用语法(obj())。
| 魔术方法 | 功能说明 | 示例代码 |
|---|---|---|
__call__(self, *args, **kwargs) | 实例被调用时执行(obj(*args)),可实现“函数对象”或“状态保持的函数”。 | python class adder: def __init__(self, base): self.base = base def __call__(self, x): return self.base + x add5 = adder(5) print(add5(3)) # 8(等价于 adder(5)(3)) |
8.2 哈希与可哈希性
__hash__ 用于计算对象的哈希值(支持作为字典键、集合元素),__eq__ 与 __hash__ 需满足:若 a == b,则 hash(a) == hash(b)。
| 魔术方法 | 功能说明 | 示例代码 |
|---|---|---|
__hash__(self) | 返回对象的哈希值(整数),未定义则默认基于内存地址。 | python class point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return (self.x, self.y) == (other.x, other.y) def __hash__(self): return hash((self.x, self.y)) # 基于属性哈希 p1 = point(1,2) p2 = point(1,2) print(hash(p1) == hash(p2)) # true d = {p1: "a"} print(d[p2]) # a(可作为字典键) |
8.3 类型转换
这类方法用于将对象转换为其他内置类型(如 int(obj)、bool(obj))。
| 魔术方法 | 对应函数 | 功能说明 | 示例代码 |
|---|---|---|---|
__int__(self) | int(obj) | 转换为整数 | python class number: def __init__(self, n): self.n = n def __int__(self): return int(self.n) num = number(3.8) print(int(num)) # 3 |
__float__(self) | float(obj) | 转换为浮点数 | - |
__bool__(self) | bool(obj) | 转换为布尔值(if obj 时调用),未定义则默认:空容器/0 为 false,否则 true。 | python class emptycheck: def __init__(self, data): self.data = data def __bool__(self): return len(self.data) > 0 ec = emptycheck([]) print(bool(ec)) # false ec2 = emptycheck([1]) print(bool(ec2)) # true |
总结
魔术方法是 python 面向对象的“灵魂”,其核心价值在于:
- 统一接口:让自定义类的行为与内置类型(如列表、字典)保持一致(如
len(obj)、for item in obj); - 灵活定制:通过重载运算符、属性访问、迭代逻辑等,实现高度定制化的类(如单例、自定义容器、上下文管理器);
- 隐式调用:无需显式调用,由 python 解释器自动触发,简化代码。
实际开发中,无需记忆所有魔术方法,而是根据需求选择(如实现 with 用 __enter__/__exit__,实现迭代用 __iter__/__next__),并遵循“最小必要”原则——仅实现需要的魔术方法,避免过度复杂。
到此这篇关于python中魔术方法功能的文章就介绍到这了,更多相关python魔术方法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论