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__
提高效率。