Python-面向对象魔术方法总结
tracemalloc
标准库tracemalloc,可以统计内存使用情况
import tracemalloc tracemalloc.start() d = [dict(zip('xy', (5, 6))) for i in range(1000000)] #237MB t = [tuple(zip('xy', (5, 6))) for i in range(1000000)] #191MB snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats: print(stat)
如下图所示,发现使用dict和tuple创建相同数量,使用的内存不一致,字段使用的内存比较多些 。

snapshot.statistics三种模式:
- snapshot.statistics('filename')
- snapshot.statistics('lineno')
- snapshot.statistics('traceback')

从上面实现可以看出内存使用上字典还是比较占用空间的
__slots__
问题的引出
字典为了提升查询的效率,必须使用空间换 时间。
一般来说一个实例,属性多一点,都存储在字典中便于查询,问题不大 。但是如果数百万个实例,那么字典占用总空间就有点大。
这个时候,能不能把属性字典__dict__省了?
Python提供了__slots__魔术方法
class A: X = 1 __slots__ = ('y', 'z') def __init__(self): self.y = 5 self.z = 6 def show(self): print(self.X, self.y) a = A() a.show() print(A.__dict__) # print(a.__dict__) #没有实例字典 #a.x = 100 #无法进行赋值 A.m = 100 # print(A.m #输出 1 5 {'__module__': '__main__', 'X': 1, '__slots__': ('y', 'z'), '__init__': <function A.__init__ at 0x00000221E1F05400>, 'show': <function A.show at 0x00000221E1F05488>, 'y': <member 'y' of 'A' objects>, 'z': <member 'z' of 'A' objects>, '__doc__': None} {'__module__': '__main__', 'X': 1, '__slots__': ('y', 'z'), '__init__': <function A.__init__ at 0x00000221E1F05400>, 'show': <function A.show at 0x00000221E1F05488>, 'y': <member 'y' of 'A' objects>, 'z': <member 'z' of 'A' objects>, '__doc__': None, 'm': 100} 100
__slots__告诉解析器,实例的属性都叫什么,一般来说,既然要节约内存,最好还是使用元组比较好,如果创建后修改少则使用元组。
一旦提供了__slots__,就阻止实例产生__dict__保存实例属性。
尝试为实例增加属性,返回AttributeError,说明实例不可以动态增加属性了。
A.m = 100是可以的,因为这个是类属性。

__slots__不影响子类实例,不会继承下去,除非子类里面自己也定义了__slots__
应用场景
使用需要构建在数百万以上众多对象,且内存容量较为紧张,实例的属性简单、固定且不用动态增加的场景。
可以使用tracemalloc查看内存使用差异,建议使用stats = snapshot.statistics('filename')查看总内存使用。
未实现和未实现异常
print(type(NotImplemented)) print(type(NotImplementedError)) raise NotImplementedError('not......') #属性 Traceback (most recent call last): File "D:/Python/test1.py", line 1304, in <module> raise NotImplementedError('not......') NotImplementedError: not...... <class 'NotImplementedType'> <class 'type'>
Notlmplemented是个值,单值,是NotlmplementedTyped的实例
NotlmplementedError是类型,是异常类,返回type
运算符重载中的反向方法
前面学习过运算符重载的方法,例如__add__和__iadd__、__radd__
可迭代对象
class A: def __init__(self): self.items =[100, 200, 300] def __iter__(self): # yield from self.items return iter(self.items) #返回一个迭代器 def __reversed__(self): return reversed(self.items) #返回一个迭代器 a = A() for x in a: print(x) print('~' * 30) for x in reversed(a): print(x) #输出 100 200 300 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 300 200 100
class B: def __init__(self): self.count = 1 def __iter__(self): print('iter~~~~~~~') return self def __next__(self): #迭代器,必须实现__iter__ 和__next__方法 print('next~~~~~~~~') self.count += 1 if self.count > 10: raise StopIteration return self.count b = B() for x in b: print(x) print('~' * 30) # print(next(b)) print(next(b, 'end~~~~~~'))
for循环in后面是一个可迭代对象,本质上调用了__iter__魔术方法拿到了一个迭代器,for循环驱动的是一个迭代器,相当于不断地调用一个迭代器的__next__方法
实现了__iter__和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,示例如下:

类提供了__iter__魔术方法,返回一个迭代器,类的实例就是可迭代对象,确切地讲是正向迭代。
如果提供了__reversed__魔术方法,返回一个迭代器,就可以使用内建函数reversed来逆向迭代
生成器
Python中由生成器表达式或生成器函数生成,快速得到迭代器的方法,生成器一定是迭代器,内部实现了迭代器的接口。

浙公网安备 33010602011771号