Python 定制类
在Python中,通过定义特殊方法(以双下划线 __ 开头和结尾的方法,也称为魔术方法),我们可以定制类的行为,使其支持内置操作,如初始化、打印、迭代、比较等。
一、对象生命周期相关
这些方法控制对象的创建、初始化和销毁,是定制类的起点。
1. __init__ - 构造器
__init__ 方法在创建类实例时自动调用,用于初始化对象的属性。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
print(person.name) # 输出: Alice
print(person.age) # 输出: 30
2. __del__ - 析构器
__del__ 方法在对象被销毁(垃圾回收)时调用,可以用来清理资源。
class Person:
def __del__(self):
print("Person object is being destroyed")
person = Person()
del person # 输出: Person object is being destroyed
二、对象显示相关方法
这些方法定义对象如何被表示为字符串,通常用于调试或用户交互。
1. __str__ - 字符串显示
__str__ 方法定义了 print() 函数调用时对象的字符串表示。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person(name={self.name}, age={self.age})"
person = Person("Alice", 30)
print(person) # 输出: Person(name=Alice, age=30)
2. __repr__ - 字符串显示
__repr__ 方法返回对象的“官方”字符串表示,通常用于调试,目标是可以通过 eval() 重建对象。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"name:{self.name}, age:{self.age})"
def __repr__(self):
return f"Person('{self.name}', {self.age})"
person = Person("Alice", 30)
print(repr(person))
# 输出: Person('Alice', 30) 这个字符串后期可以用 eval 创建实例
比如在控制台中默认显示的就是 __repr__
>>>
>>> class Person:
... def __init__(self, name, age):
... self.name = name
self.age = age
... self.age = age
... def __str__(self):
... return f"name:{self.name}, age:{self.age})"
... def __repr__(self):
... return f"Person('{self.name}', {self.age})"
...
>>>
>>> Person("Alice", 30)
Person('Alice', 30)
>>>
>>>
>>> print(Person("Alice", 30))
name:Alice, age:30)
>>>
>>> 三、容器操作相关方法
这些方法使类像内置容器(如列表、字典)一样支持长度计算、索引和迭代。
1. __len__ - 返回对象的长度
__len__ 方法允许使用 len() 函数获取对象的长度。
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3, 4])
print(len(my_list)) # 输出: 4
2. __getitem__ 和 __setitem__
__getitem__ 用于访问元素,__setitem__ 用于设置元素,支持 obj[key] 语法。
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
my_list = MyList([1, 2, 3, 4])
print(my_list[2]) # 输出: 3
my_list[2] = 10
print(my_list[2]) # 输出: 10
3. __iter__ 和 __next__ - 迭代
__iter__ 返回迭代器,__next__ 定义迭代行为,使对象支持 for 循环。
class MyList:
def __init__(self, items):
self.items = items
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.items):
item = self.items[self.index]
self.index += 1
return item
else:
raise StopIteration
my_list = MyList([1, 2, 3, 4])
for item in my_list:
print(item) # 输出: 1 2 3 4
四、比较与哈希相关方法
这些方法定义对象的相等性比较和哈希行为,适用于集合或字典键。
1. __eq__ - 相等性比较
__eq__ 方法定义两个对象是否相等,使用 == 运算符时调用。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
person1 = Person("Alice", 30)
person2 = Person("Alice", 30)
print(person1 == person2) # 输出: True
2. __hash__ - 哈希值
__hash__ 方法返回对象的哈希值,使对象可用作字典键或集合元素。需与 __eq__ 一致。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
def __hash__(self):
return hash((self.name, self.age))
person = Person("Alice", 30)
my_dict = {person: "data"}
print(my_dict[person]) # 输出: data
五、其他高级定制方法
这些方法提供更多功能,如上下文管理、可调用对象等。
1. __call__ - 对象可调用
__call__ 方法使对象可以像函数一样被调用。
class MyCallable:
def __call__(self, *args, **kwargs):
print("Called with:", args, kwargs)
callable_obj = MyCallable()
callable_obj(1, 2, a=3, b=4) # 输出: Called with: (1, 2) {'a': 3, 'b': 4}
对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。
我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,使用 callable方法可以判断。
class MyCallable:
def __call__(self, *args, **kwargs):
print("Called with:", args, kwargs)
print(callable(MyCallable)) # True
print(callable([1, 2, 3, 4])) # False
2. __enter__ 和 __exit__
__enter__ 和 __exit__ 方法支持 with 语句,用于上下文资源管理。
class MyContext:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting the context")
with MyContext() as ctx:
print("Inside the context")
# 输出:
# Entering the context
# Inside the context
# Exiting the context
六、性能优化相关属性
1. __slots__ - 限制属性
__slots__ 属性限制实例的动态属性,减少内存使用并提高访问速度。
class Person:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
print(person.name) # 输出: Alice
person.address = "Unknown" # 这会引发 AttributeError
__slots__ 的作用
- 节省内存:
- 默认情况下,Python 类的实例使用
__dict__存储属性,这是一个字典,占用较多内存。 - 使用
__slots__后,Python 不会为实例创建__dict__,而是使用固定大小的内存空间来存储属性,从而显著减少内存占用。 - 尤其在需要创建大量实例时,内存节省效果明显。
- 默认情况下,Python 类的实例使用
- 限制属性动态添加:
__slots__防止实例动态添加不在__slots__定义中的属性,有助于避免因拼写错误或意外添加属性导致的 bug。- 提高代码的健壮性和可维护性。
- 提高属性访问速度:
- 由于
__slots__消除了__dict__的开销,属性访问不再需要通过字典查找,而是直接通过偏移量访问,速度略有提升。
- 由于
总结
通过以上特殊方法和属性,我们可以全面定制类的行为:
- 生命周期:
__init__和__del__控制对象的创建和销毁。 - 表示:
__str__和__repr__定义对象的字符串形式。 - 容器操作:
__len__、__getitem__、__setitem__、__iter__、__next__模拟容器行为。 - 比较与哈希:
__eq__和__hash__支持比较和哈希操作。 - 高级功能:
__call__和__enter__/__exit__提供额外的灵活性。 - 性能优化:
__slots__提高效率。