Python中的魔术方法
类相关
对象生命周期
__new__
方法
普通类中
它通常用于自定义对象的创建过程。__new__
的主要任务是创建并返回一个类的实例。通常,它会调用父类的 __new__
方法来完成实际的实例创建。
def __new__(cls, *args, **kwargs):
pass
- cls:当前类的引用,即调用 new 的类。
- *args:传递给构造函数的额外位置参数。
- **kwargs:传递给构造函数的额外关键字参数。
class MyClass:
def __init__(self, value):
print(f"Initializing instance with value: {value}")
self.value = value
def __new__(cls, *args, **kwargs):
print(f"Creating instance of {cls.__name__} with args: {args} and kwargs: {kwargs}")
instance = super().__new__(cls) # 调用父类的 __new__ 创建实例
return instance
# 创建实例
obj = MyClass(123, key="value")
元类中
当 __new__
用于元类时,它用于控制类的创建过程。
元类的 __new__
方法的主要任务是创建并返回一个类对象。通常,它会调用父类的 __new__
方法来完成实际的类创建。
def __new__(cls, name, bases, dct, **kwargs):
pass
- cls:当前元类的引用,即调用
__new__
的元类。 - name:新创建的类的名称。
- bases:新创建的类的基类元组。
- dct:包含类的属性和方法的字典。
- **kwargs:传递给元类的额外关键字参数。
class MyMeta(type):
def __new__(cls, name, bases, dct, **kwargs):
print(f"Creating class {name} with bases: {bases} and attributes: {dct}")
print(f"Additional kwargs: {kwargs}")
return super().__new__(cls, name, bases, dct)
# 使用自定义元类创建类
class MyClass(metaclass=MyMeta, extra="info"):
attr = "value"
输出
Creating class MyClass with bases: () and attributes: {'__module__': '__main__', '__qualname__': 'MyClass', 'attr': 'value'}
Additional kwargs: {'extra': 'info'}
__init__
__init__
是实例化对象时的初始化方法。
class MyClass:
def __init__(self, value):
self.value = value
obj = MyClass(20)
print(obj.value) # 输出:20
__del__
在对象被销毁时被调用。
class MyClass:
def __del__(self):
print("Object is being destroyed")
obj = MyClass()
del obj # 输出:Object is being destroyed
上下文管理
__enter__
和 __exit__
用于定义对象的上下文管理行为,通常用于 with 语句。
class MyResource:
def __enter__(self):
print("Resource is being acquired")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Resource is being released")
with MyResource():
print("Inside the with block")
# 输出:
# Resource is being acquired
# Inside the with block
# Resource is being released
属性操作
__getattr__
用于定义访问不存在的属性时的行为。
class MyClass:
def __getattr__(self, name):
return f"Attribute {name} not found"
obj = MyClass()
print(obj.unknown) # 输出:Attribute unknown not found
__setattr__
用于定义设置属性时的行为。
class MyClass:
def __setattr__(self, name, value):
if name == "value":
self.__dict__[name] = value
else:
raise AttributeError(f"Cannot set attribute {name}")
obj = MyClass()
obj.value = 10
try:
obj.other = 20
except AttributeError as e:
print(e) # 输出:Cannot set attribute other
__getattribute__
用于定义访问任何属性时的行为。
class MyClass:
def __init__(self, value):
self.value = value
def __getattribute__(self, name):
print(f"Accessing attribute {name}")
return super().__getattribute__(name)
obj = MyClass(30)
print(obj.value) # 输出:Accessing attribute value 30
运算符重载
__add__
用于定义对象的加法操作。
class MyClass:
def __init__(self, value):
self.value = value
def __add__(self, other):
if isinstance(other, MyClass):
return MyClass(self.value + other.value)
return NotImplemented
obj1 = MyClass(10)
obj2 = MyClass(20)
obj3 = obj1 + obj2
print(obj3.value) # 输出:30
__eq__
class Point:
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 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # 输出: True
__lt__
用于定义对象的小于关系。
class MyClass:
def __init__(self, value):
self.value = value
def __lt__(self, other):
if isinstance(other, MyClass):
return self.value < other.value
return NotImplemented
obj1 = MyClass(30)
obj2 = MyClass(40)
print(obj1 < obj2) # 输出:True
类型转换
__str__
用户友好字符串表示
class Book:
def __str__(self):
return "《Python 核心编程》"
b = Book()
print(str(b)) # 输出: 《Python 核心编程》
__repr__
返回对象的“官方”字符串表示,通常用于调试。
class MyClass:
def __init__(self, value):
self.value = value
def __repr__(self):
return f"MyClass(value={self.value})"
obj = MyClass(40)
print(repr(obj)) # 输出:MyClass(value=40)
容器操作
__getitem__
用于定义通过索引访问元素的行为。
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, key):
return self.items[key]
my_list = MyList([1, 2, 3])
print(my_list[1]) # 输出:2
__setitem__
用于定义通过索引设置元素的行为。
class MyList:
def __init__(self, items):
self.items = items
def __setitem__(self, key, value):
self.items[key] = value
my_list = MyList([1, 2, 3])
my_list[1] = 10
print(my_list.items) # 输出:[1, 10, 3]
__iter__
用于定义对象的迭代行为。
class MyList:
def __init__(self, items):
self.items = items
def __iter__(self):
return iter(self.items)
my_list = MyList([1, 2, 3])
for item in my_list:
print(item) # 输出:1 2 3
__slots__
是一个类属性,用于限制实例的属性,并优化内存使用。通过定义 __slots__
,可以明确指定类实例允许拥有的属性,防止动态添加其他属性。这不仅可以减少内存占用,还可以提高属性访问速度。
基本用法
是一个包含字符串的列表或元组,每个字符串代表一个允许的属性名。
class MyClass:
__slots__ = ("attr1", "attr2")
def __init__(self, value1, value2):
self.attr1 = value1
self.attr2 = value2
obj = MyClass(10, 20)
print(obj.attr1) # 输出:10
print(obj.attr2) # 输出:20
# 尝试添加未定义的属性
try:
obj.attr3 = 30
except AttributeError as e:
print(e) # 输出:'MyClass' object has no attribute 'attr3'
节省内存
可以显著减少每个实例的内存占用,因为它避免了为每个实例创建一个完整的 __dict__
。
import sys
class MyClass:
__slots__ = ("attr1", "attr2")
class MyNormalClass:
pass
obj1 = MyClass(10, 20)
obj2 = MyNormalClass()
obj2.attr1 = 10
obj2.attr2 = 20
print(sys.getsizeof(obj1)) # 输出:48
print(sys.getsizeof(obj2)) # 输出:88
__slots__
继承与 当类继承自带有 __slots__
的父类时,子类需要显式地定义自己的 __slots__
, 否则子类实例会自动拥有一个 __dict__
,从而抵消了节省内存的效果。
# 子类不定义 __slots__
class Parent:
__slots__ = ("parent_attr",)
class Child(Parent):
pass # 没有定义 __slots__
obj = Child()
obj.parent_attr = 10
obj.child_attr = 20 # 子类实例有 __dict__,可以动态添加属性
# 子类定义 __slots__
class Parent:
__slots__ = ("parent_attr",)
class Child(Parent):
__slots__ = ("child_attr",) # 子类显式定义 __slots__
obj = Child()
obj.parent_attr = 10
obj.child_attr = 20
try:
obj.new_attr = 30
except AttributeError as e:
print(e) # 输出:'Child' object has no attribute 'new_attr'
__slots__
与 __dict__
使用 如果需要在使用__slots__
的同时保留 __dict__
,可以在 __slots__
中显式地添加 __dict__
。
class MyClass:
__slots__ = ("attr1", "attr2", "__dict__")
def __init__(self, value1, value2):
self.attr1 = value1
self.attr2 = value2
self.extra_attr = 30 # 动态添加的属性
obj = MyClass(10, 20)
print(obj.attr1) # 输出:10
print(obj.attr2) # 输出:20
print(obj.extra_attr) # 输出:30
← Previous postPython中的Collection集合类
Next post →Python中元类编程详解