Python 中的魔法函数,也被称为特殊方法或双下划线方法,是 Python 中一些特殊命名的函数,它们以双下划线开头和结尾。这些函数定义了对象在特定情况下的行为,例如创建、比较、运算、迭代等。
魔法函数主要是为某些特殊需求而设计的。例如__str__() 和__repr__() 函数用于打印输出对象的信息,__add__() 函数用于定义两个对象相加的行为,__len__() 函数定义当被 len() 调用时的行为等。Python 魔法函数是实现 Python 语法糖的一种方式,提高代码的可读性和可维护性,比如对象相加,大家更习惯 c = a + b 的形式,如果用户使用 a + b 能自动调用 a.__add__(b) 的话,自然要方便很多了,而魔法函数正好有这种功能。
__init__ 对象初始化函数,在创建实例化对象时自动调用。这个最熟悉的就不多说了。
1 2 3 4 5 |
class TestClass: def __init__(self, name): self.name = name
obj = TestClass("Alice") |
以用户友好的方式返回对象的字符串表示,使用 str() 时自动调用。
1 2 3 4 5 6 7 8 9 10 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __str__(self): return f"({self.x}, {self.y})"
p = PointClass(3, 4) print(p) # (3, 4) |
以开发者友好的方式返回对象的字符串表示,使用 repr() 时自动调用。当使用 print() 函数打印对象时,首先调用的是 __str__ 方法,如果对象没有定义 __str__ 方法,才会调用 __repr__ 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __str__(self): return f"({self.x}, {self.y})"
def __repr__(self): return f"Point({self.x}, {self.y})"
p = PointClass(3, 4) print(p) # (3, 4) print(str(p)) # (3, 4) print(repr(p)) # Point(3, 4) |
返回对象的长度,使用 len() 自动调用。
1 2 3 4 5 6 7 8 9 |
class ListClass: def __init__(self, items): self.items = items
def __len__(self): return len(self.items)
my_list = ListClass([1, 2, 3, 4, 5]) print(len(my_list)) # 5 |
当尝试访问字典中不存在的键时,如果定义了 __missing__ 方法,它将被调用,而不是抛出 KeyError。
1 2 3 4 5 6 7 8 9 10 11 12 |
class DictClass(dict):
def __missing__(self, key): self[key] = "default" return "default"
my_dict = DictClass({'a': 1, 'b': 2}) print(my_dict['c']) # default print(my_dict.keys()) # dict_keys(['a', 'b', 'c'])
my_dict = dict({'a': 1, 'b': 2}) print(my_dict['c']) # KeyError: 'c' |
获取对象的指定元素,当使用索引操作符[]来访问对象的元素时自动调用。
1 2 3 4 5 6 7 8 9 |
class DictClass: def __init__(self, items): self.items = items
def __getitem__(self, key): return self.items.get(key)
my_dict = DictClass({'a': 1, 'b': 2}) print(my_dict['a']) # 1 |
给对象的指定元素设置值,给对象设定值时自动调用。
1 2 3 4 5 6 7 8 9 10 |
class DictClass: def __init__(self, items): self.items = items
def __setitem__(self, key, value): self.items[key] = value
my_dict = DictClass({'a': 1, 'b': 2}) my_dict['c'] = 3 print(my_dict.items) # {'a': 1, 'b': 2, 'c': 3} |
删除对象指定元素,使用 del 删除对象元素时自动调用。
1 2 3 4 5 6 7 8 9 10 |
class DictClass: def __init__(self, items): self.items = items
def __delitem__(self, key): del self.items[key]
my_dict = DictClass({'a': 1, 'b': 2}) del my_dict['a'] print(my_dict.items) # {'b': 2} |
判断对象是否包含指定元素,使用 in 判断时自动调用。
1 2 3 4 5 6 7 8 9 |
class ListClass: def __init__(self, items): self.items = items
def __contains__(self, item): return item in self.items
my_list = ListClass([1, 2, 3, 4, 5]) print(3 in my_list) # True |
返回迭代器对象。
1 2 3 4 5 6 7 8 9 10 |
class ListClass: def __init__(self, items): self.items = items
def __iter__(self): return iter(self.items)
my_list = ListClass([1, 2, 3, 4, 5]) for item in my_list: print(item) # 依次输出: 1, 2, 3, 4, 5 |
返回迭代器的下一个元素,循环遍历获取对象元素时自动调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class ListClass: def __init__(self, items): self.items = items self.index = 0
def __iter__(self): return self
def __next__(self): if self.index >= len(self.items): raise StopIteration value = self.items[self.index] self.index += 1 return value
my_list = ListClass([1, 2, 3, 4, 5]) for item in my_list: print(item) # 依次输出: 1, 2, 3, 4, 5 |
判断两个对象是否相等,两个对象使用 == 判断时自动调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __eq__(self, other): return self.x == other.x and self.y == other.y
p1 = PointClass(3, 4) p2 = PointClass(3, 4) p3 = PointClass(5, 6) print(p1 == p2) # True print(p1 == p3) # False |
输出对象的绝对值。
1 2 3 4 5 6 7 8 9 10 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __abs__(self): return (self.x * self.x + self.y * self.y) ** 0.5
p1 = PointClass(3, 4) print(abs(p1)) # 5.0 |
判断一个对象是否小于另一个对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __lt__(self, other): return self.x < other.x and self.y < other.y
p1 = PointClass(3, 4) p2 = PointClass(3, 4) p3 = PointClass(5, 6) print(p1 < p2) # False print(p1 < p3) # True |
判断一个对象是否小于或等于另一个对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __le__(self, other): return self.x <= other.x and self.y <= other.y
p1 = PointClass(3, 4) p2 = PointClass(3, 4) p3 = PointClass(5, 6) print(p1 <= p2) # True print(p1 <= p3) # True |
判断一个对象是否大于另一个对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __gt__(self, other): return self.x > other.x and self.y > other.y
p1 = PointClass(3, 4) p2 = PointClass(3, 4) p3 = PointClass(1, 2) print(p1 > p2) # False print(p1 > p3) # True |
判断一个对象是否大于或等于另一个对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __ge__(self, other): return self.x >= other.x and self.y >= other.y
p1 = PointClass(3, 4) p2 = PointClass(3, 4) p3 = PointClass(1, 2) print(p1 >= p2) # True print(p1 >= p3) # True |
定义对象的加法操作,对象之间使用 + 自动调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __add__(self, other): return PointClass(self.x + other.x, self.y + other.y)
def __str__(self): return f"({self.x}, {self.y})"
p1 = PointClass(1, 2) p2 = PointClass(3, 4) print(p1 + p2) # (4, 6) |
定义对象的减法操作,对象之间使用 - 自动调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __sub__(self, other): return PointClass(self.x - other.x, self.y - other.y)
def __str__(self): return f"({self.x}, {self.y})"
p1 = PointClass(1, 2) p2 = PointClass(3, 4) print(p1 - p2) # (-2, -2) |
定义对象的乘法操作,对象之间使用 * 自动调用,可以根据操作数类型进行对象乘法和数乘。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class PointClass: def __init__(self, x, y): self.x = x self.y = y
def __mul__(self, other): if isinstance(other, PointClass): return PointClass(self.x * other.x, self.y * other.y) elif isinstance(other, int) or isinstance(other, float): return PointClass(self.x * other, self.y * other) else: raise TypeError(f"Unsupported operand type: {type(other)}")
def __str__(self): return f"({self.x}, {self.y})"
p1 = PointClass(1, 2) p2 = PointClass(3, 4) print(p1 * p2) # (3, 8) print(p1 * 3) # (3, 6) print(p1 * "t") # TypeError: Unsupported operand type: <class 'str'> |
使对象可调用。
1 2 3 4 5 6 7 8 9 10 11 12 |
class Calculator:
def __init__(self, x, y): self.x = x self.y = y
def __call__(self): return self.x + self.y
calc = Calculator(3, 4) result = calc() print(result) # 7 |
1 2 3 4 5 6 7 |
class Calculator: def __call__(self, a, b): return a + b
calc = Calculator() result = calc(3, 4) print(result) # 7 |
在访问对象不存在的属性时调用。
1 2 3 4 5 6 |
class Person: def __getattr__(self, name): return f"Attribute '{name}' does not exist."
p = Person() print(p.age) # Attribute 'age' does not exist. |
当设置类实例属性时自动调用。
1 2 3 4 5 6 7 8 |
class Person: def __setattr__(self, name, value): print(f"Setting attribute '{name}' to '{value}'") super().__setattr__(name, value)
p = Person() p.name = "Alice" # Setting attribute 'name' to 'Alice' print(p.name) # Alice |
删除对象属性时自动调用。
1 2 3 4 5 6 7 8 9 10 |
class Person: def __delattr__(self, name): print(f"Deleting attribute '{name}'") super().__delattr__(name)
p = Person() p.name = "Alice" print(p.name) # Alice del p.name # Deleting attribute 'name' print(p.name) # AttributeError: 'Person' object has no attribute 'name |
__enter__() 方法用于进入上下文管理器所定义的代码块之前执行的操作。
上下文管理器的 __exit__() 方法还有三个参数,即异常类型、异常值和追踪信息。如果在 with 语句块中发生了异常,这些参数会传递给 __exit__() 方法,可以在该方法中进行相关的处理。
当对象不再被引用时,Python的垃圾回收机制会调用这个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class FileHandler: def __init__(self, filename): self.filename = filename
def __enter__(self): print("goto __enter__ open file") self.file = open(self.filename, 'w', encoding='utf-8') return self.file
def __exit__(self, exc_type, exc_val, exc_tb): print("goto __exit__ close file") self.file.close()
def __del__(self): print("goto __del__ release resource")
print("process start") with FileHandler("./test.txt") as f: f.write("hello world!\n") print("process end") # process start # goto __enter__ open file # goto __exit__ close file # goto __del__ release resource # process end |
__dict__ 包含通过 __init__方法初始化的属性和值。
1 2 3 4 5 6 7 8 9 10 |
class TestClass: def __init__(self, name): self.name = name
def test(self): self.age = 25
obj = TestClass("Alice") print(obj.__dict__) # {'name': 'Alice'} # print(TestClass.__dict__) |
内置类属性__slots__是一个特殊的内置类属性,它可以用于定义类的属性名称的集合。一旦在类中定义了__slots__属性,Python 将限制该类的实例只能拥有__slots__中定义的属性。
1 2 3 4 5 6 7 8 9 10 11 12 |
class Person: __slots__ = ('name', 'age')
def __init__(self, name, age): self.name = name self.age = age self.address = "" # AttributeError: 'Person' object has no attribute 'address'
person = Person("Alice", 30) print(person.name) # 输出 "Alice" print(person.age) # 输出 30 print(person.__slots__) # ('name', 'age') |