接上篇:一文掌握python面向对象魔术方法(一)-CSDN博客
目录
六、迭代和序列化:
1、__iter__(self): 定义迭代器,使得类可以被 for 循环迭代。
2、__getitem__(self, key): 定义索引操作,如 obj[key]。
3、__setitem__(self, key, value): 定义赋值操作,如 obj[key] = value。
4、__delitem__(self, key): 定义删除操作,如 del obj[key]。
5、__len__(self): 定义长度获取,如 len(obj)。
6、__reversed__(self): 定义反向迭代。
七、上下文管理:
1、__enter__(self): 实现上下文管理协议(context management protocol)。
2、__exit__(self, exc_type, exc_value, traceback): 退出上下文管理器时调用。与 __enter__ 方法配对使用。
八、类型转换:
1、__bool__(self): 定义布尔测试,即 if obj 是否为真。
2、__int__(self): 定义对象转换为整数。
3、__float__(self): 定义对象转换为浮点数。
4、__complex__(self): 定义对象转换为复数。
5、__hash__(self): 定义对象的哈希值,以便放入集合和作为字典键。
九、反射与描述符:
1、__class__(self): 提供对象所属类的引用。
2、__dir__(self): 列出对象公开的属性名。
3、__get__(self, instance, owner): 在描述符协议中,定义当访问属性时的行为。
4、__set__(self, instance, value): 在描述符协议中,定义当设置属性时的行为。
5、__delete__(self, instance): 在描述符协议中,定义当删除属性时的行为。
6、__call__:使得一个对象可以像函数那样被调用
十、元类和类方法:
1、__metaclass__: (Python 2 中)定义类的元类。
2、__prepare__(metacls, name, bases, **kwds): Python 3 引入的元类方法,控制类字典的初始准备阶段。
3、__mro__: 返回方法解析顺序 (Method Resolution Order),即类继承层次结构中方法查找的顺序。
4、__subclasses__(cls): 返回当前类的所有直接子类列表。
十一、特殊属性访问:
1、__slots__: 在类中定义后,限制类实例可用的属性,节省内存。
2、__module__: 类所在的模块名称,通常是一个字符串形式的模块路径。
十二、复制与深浅拷贝:
1、__copy__(self): 用于实现浅复制功能。
2、__deepcopy__(self, memo): 用于实现深复制功能。
1、__iter__(self)
: 定义迭代器,使得类可以被 for
循环迭代。当调用迭代器的__iter__()
方法时,它会返回一个迭代器对象,该对象能够通过next()
函数或者for循环等来逐个访问容器中的元素。
这个方法的主要目的是使对象变成可迭代的。也就是说,如果一个类定义了__iter__()
方法,那么这个类的对象就可以在for循环中直接使用,或者通过其他需要迭代器的上下文使用。
class MyIterable:
def __init__(self, items):
self.items = items
def __iter__(self):
return iter(self.items)
my_obj = MyIterable([1, 2, 3])
for item in my_obj:
print(item)
在这个例子中,MyIterable
类通过定义__iter__
方法使其变得可迭代,当在for循环中使用my_obj
时,会调用其__iter__
方法返回一个迭代器,然后依次获取并打印列表中的每个元素。
2、__getitem__(self, key)
: 定义索引操作,如 obj[key]
。当尝试从对象中通过下标(索引)或切片获取值时,Python解释器会自动调用此方法。
例如,如果有一个类实例,并尝试像操作列表或字典那样通过索引获取元素,如 instance[0]
或 instance[1:3]
,那么实际上就是在调用该类的__getitem__(self, key)
方法。
class CustomList:
def __init__(self, data):
self.data = data
def __getitem__(self, key):
return self.data[key]
custom_list = CustomList([1, 2, 3, 4, 5])
print(custom_list[0]) # 输出:1
print(custom_list[1:3]) # 输出:[2, 3]
在这个例子中,CustomList类重载了__getitem__
方法,使得我们可以像操作普通列表一样通过索引来获取数据。当执行custom_list[0]
或custom_list[1:3]
时,实际上是调用了custom_list.__getitem__(0)
和custom_list.__getitem__(slice(1, 3))
。
3、__setitem__(self, key, value)
: 定义赋值操作,如 obj[key] = value
。它在尝试通过索引赋值操作来修改对象内容时被调用。当你对一个对象执行类似 instance[key] = value
的操作时,Python解释器会自动调用这个方法。
例如,在自定义类中实现__setitem__
方法可以允许用户像操作列表或字典那样设置元素的值:
class CustomList:
def __init__(self, data=None):
if data is None:
self.data = []
else:
self.data = data
def __setitem__(self, key, value):
self.data[key] = value
custom_list = CustomList([1, 2, 3, 4, 5])
custom_list[0] = 10 # 这里会调用 __setitem__
print(custom_list.data) # 输出:[10, 2, 3, 4, 5]
# 对于可变长度的键,如切片,也可以支持:
custom_list[1:3] = [11, 12] # 这也需要 __setitem__ 方法正确处理切片赋值
print(custom_list.data) # 输出:[10, 11, 12, 4, 5]
在上述示例中,CustomList 类通过覆盖 __setitem__
方法实现了索引赋值功能,使得可以直接使用下标修改类实例内部的数据成员。对于更复杂的操作,如切片赋值,可能需要进一步扩展该方法以处理不同类型的键。
实现切片赋值:
class CustomList:
def __init__(self, data=None):
self.data = [] if data is None else list(data)
def __setitem__(self, key, value):
if isinstance(key, slice):
start, stop, step = key.start, key.stop, key.step
if start is None:
start = 0
if stop is None:
stop = len(self.data)
if step is None:
step = 1
indices = range(start, stop, step)
for i, v in zip(indices, value):
if i < 0:
i += len(self.data)
if i < 0 or i >= len(self.data):
raise IndexError("Index out of range")
self.data[i] = v
else:
if key < 0:
key += len(self.data)
if key < 0 or key >= len(self.data):
raise IndexError("Index out of range")
self.data[key] = value
# 使用示例
cl = CustomList([0, 1, 2, 3, 4, 5])
cl[1:4] = [10, 20, 30]
print(cl.data) # 输出: [0, 10, 20, 30, 4, 5]
在这个例子中,当我们在自定义列表类CustomList
上调用切片赋值时,__setitem__
方法首先检查key是否为slice类型。如果是,它将解析切片的开始、结束和步长,并根据这些值遍历索引,然后逐个赋值。如果不是切片,它就按照常规索引进行赋值。
4、__delitem__(self, key)
: 定义删除操作,如 del obj[key]
。主要用于在用户尝试删除类实例中的某个项目时执行相应的操作。当你对类实例使用 del 关键字或通过索引/切片表达式删除元素时,Python 解释器会调用这个方法。
例如,在一个自定义列表类中,__delitem__
方法可以这样实现以支持索引或切片删除:
class CustomList:
def __init__(self, data=None):
self.data = [] if data is None else list(data)
def __delitem__(self, key):
if isinstance(key, slice):
start, stop, step = key.indices(len(self.data))
# self.data.__delslice__(start, stop, step) # 旧版 Python
self.data[start:stop:step] = self.data[:start] + self.data[stop:] # 新版本 Python
else:
if key < 0:
key += len(self.data)
if key < 0 or key >= len(self.data):
raise IndexError("Index out of range")
del self.data[key]
# 使用示例
cl = CustomList([0, 1, 2, 3, 4, 5])
del cl[1:4]
print(cl.data) # 输出: [0, 4, 5]
# 注意:对于现代Python(3.x),无需手动处理切片删除,可以直接使用 del cl[1:4],因为Python内置列表会自动处理这种情况。
对于 Python 3.x,由于 __delslice__
已经被废弃,直接使用 del cl[1:4]
即可,因为在 Python 内置的列表对象中,已经内置了对切片删除的支持,不需要额外处理。上述代码仅适用于需要在自定义类中模拟列表行为的情况,而在现代 Python 版本中,您可以直接使用内置列表的功能,无需覆盖 __delitem__
方法处理切片删除。
5、__len__(self)
: 定义长度获取,如 len(obj)
。当对象的 len()
函数被调用时,Python 会自动调用这个方法。在自定义类中,重写 __len__
方法可以让用户轻松获取对象所包含元素的数量。
例如,如果想创建一个自定义列表类,并希望用户能够使用 len()
函数获取列表中元素的数量,你可以在类中添加 __len__
方法:
class CustomList:
def __init__(self, data=None):
self.data = [] if data is None else list(data)
def __len__(self):
return len(self.data)
# 使用示例
cl = CustomList([0, 1, 2, 3, 4, 5])
print(len(cl)) # 输出: 6
在这个例子中,当调用 len(cl)
时,Python 将自动调用 cl
实例的 __len__
方法,返回自定义列表 data
属性中的元素数量。
6、__reversed__(self)
: 定义反向迭代。在类中定义时,允许该类的对象能够被内置的 reversed()
函数调用以实现反向迭代。
这个方法应该返回一个迭代器,该迭代器生成对象元素的反向序列。例如,如果有一个自定义列表类,可以这样实现 __reversed__
方法:
class MyList:
def __init__(self, elements):
self.elements = elements
def __reversed__(self):
return reversed(self.elements)
# 使用示例
my_list = MyList([1, 2, 3, 4, 5])
for item in reversed(my_list):
print(item) # 5, 4, 3, 2, 1
1、__enter__(self)
: 实现上下文管理协议(context management protocol)。当对象作为 with
语句的目标表达式时,该方法会被自动调用。它的主要作用是初始化进入某个特定上下文所需的资源,并返回一个对象供 with
语句块内部使用。
例如,在一个实现了上下文管理协议的类中,__enter__
方法可能会打开一个文件、创建一个数据库连接或其他需要在使用完毕后清理的资源:
class ManagedResource:
def __enter__(self):
# 打开或者初始化资源
self.resource = open("example.txt", "r")
return self.resource # 返回资源对象,可以在这个资源上执行操作
def __exit__(self, exc_type, exc_value, traceback):
# 使用完资源后关闭或清理
self.resource.close()
# 使用with语句来自动管理资源
with ManagedResource() as resource:
content = resource.read()
# 在此处对resource进行操作,完成后无需手动关闭,__exit__会确保资源正确关闭
在这个例子中,当 ManagedResource
类的对象进入 with
语句的作用域时,__enter__
方法会被调用,返回打开的文件对象;当 with
语句块结束时,无论是否发生异常,__exit__
方法都会被调用来关闭文件并可能处理任何异常情况。
2、__exit__(self, exc_type, exc_value, traceback)
: 退出上下文管理器时调用。与 __enter__
方法配对使用。当离开 with
语句块时,不论是因为正常执行完成还是抛出了异常,__exit__
方法都会被调用。
这个方法接收三个参数:
exc_type
: 如果在 with
语句块内发生了异常,那么这是异常的类型(如 TypeError
、ValueError
等)。如果没有异常,则为 None
。exc_value
: 如果有异常,这是异常实例本身。若无异常,则为 None
。traceback
: 如果有异常,这是跟踪回溯对象。若无异常,则为 None
。__exit__
方法的主要职责是清理在 __enter__
中获取或创建的资源,包括但不限于关闭文件、释放锁、删除临时变量等,并且可以根据需要处理在 with
语句块中发生的异常。
如果