在Python中有许多以__开头的变量,这些变量是什么意思呢?这里介绍下[__dir__, __slots__, __weakref__,__missing__, __contains__]
__dir__ -> 看个小例子就知道了
In[1]:classT(object): ...:pass ...: In[2]:t=T() In[3]:t.<Tab>
啥也没有...
In[4]:classT2(object): ...:def__dir__(self): ...:return['a','b'] ...: In[5]:t=T2() In[6]:t. t.at.b In[7]:dir(t) Out[7]:['a','b']
看出来了把, 不解释, 但是这个__dir__是相对于类的实例有效果的.
__slots__
这个在我初学python的时候就被模糊了, 原来的理解是它的出现替代了__dict__,也就是说你只能给__slots__ 这个变量列表项的属性赋值. 对外的接口减少了,也安全了. 后来看了这篇Saving 9 GB of RAM with Python’s slots. 好久不做运维了,在生产环境究竟怎么样我无法定论, 也提到了,在对象实例很多的时候他能帮助减少内存, 详见https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch08s04.html. 这里来个小实验(在Hacker News也被讨论过https://news.ycombinator.com/item?id=6750187)
代码例子(我对细节做注释):
#coding=utf-8 importsys fromitertoolsimportstarmap,product classSlotTest(object): #__slots__=['x','y','z']主要对比去掉这句和包含这句程序内存占用 def__init__(self,x,y,z): self.x=x self.y=y self.z=z def__str__(self): return"{}{}{}".format(self.x,self.y,self.z) p=product(range(10000),range(20),[4])#创建0-1000&0-20&4的笛卡尔积 a=list(starmap(SlotTest,p))#相当于对每个SlotTest实例化,实例化的格式是p的长度 printa[0] sys.stdin.read(1)
结果对比:
$pmap-x`ps-ef|greptest_slot.py|grep-vgrep|awk'{print$2}'`|greptotal#未使用__slots__ totalkB1034967648073728 $pmap-x`ps-ef|greptest_slot.py|grep-vgrep|awk'{print$2}'`|greptotal#使用了__slots__ totalkB499602288820136
结果很明显,内存占用减少了很多...
__weakref__ 弱引用
首先先说下weakref: 弱引用,与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收. 在Python中,当一个对象的引用数目为0的时候,才会被从内存中回收. 但是被循环引用呢?
In[1]:importweakref In[2]:importgc In[3]:classObj(object): ...:defa(self): ...:return1 ...: In[4]:obj=Obj() In[5]:s=obj In[6]:gc.collect()#不可达引用对象的数量 Out[6]:3 In[7]:printsisobj True In[8]:obj=1#最初的被引用的对象改变了. In[9]:gc.collect() Out[9]:0 In[10]:sisNone#s还是指向了Obj引用计数为1 Out[10]:False In[11]:s Out[11]:<__main__.Objat0x2b36510> ----华丽的分割一下 In[12]:obj=Obj() In[13]:r=weakref.ref(obj)#让obj变成那个弱引用 In[14]:gc.collect() Out[14]:211 In[15]:r()isobj True In[16]:obj=1 In[17]:gc.collect() Out[17]:0 In[18]:r()isNone#弱引用计数器没有增加,所以当obj不在引用Obj的时候,Obj对象就被释放了 Out[18]:True
好吧, 我的总结是弱引用是个好东西, 但是加了__slots__就不支持弱引用了. 所以需要__weakref__
In[9]:classT3(object): ...:__slots__=[] ...: In[10]:classT4(object): ....:__slots__='__weakref__'#这样就支持了weakref ....: In[11]:importweakref In[12]:t3=T3() In[13]:t4=T4() In[14]:weakref.ref(t3) --------------------------------------------------------------------------- TypeErrorTraceback(mostrecentcalllast) <ipython-input-14-bdb7ab7ac3bc>in<module>() ---->1weakref.ref(t3) TypeError:cannotcreateweakreferenceto'T3'object In[15]:weakref.ref(t4) Out[15]:<weakrefat0x2766f70;to'T4'at0x2586fd8>
__contains__ 判断某值 in/not in 实例
In[1]:classNewList(object): ...:def__init(self,values): ...:self.values=values ...:def__contains__(self,value): ...:returnvalueinself.values ...: In[2]:l=NewList([1,2,3,4]) In[3]:4inl Out[3]:True In[4]:10inl Out[4]:False __missing__
最初看这个特殊方法是看python标准库的源码的时候(collections#L421):
classCounter(dict): ... def__missing__(self,key): 'ThecountofelementsnotintheCounteriszero.' #Neededsothatself[missing_item]doesnotraiseKeyError return0
什么意思呢?
In[6]:c=collections.Counter({'a':1}) In[7]:c['b']#没有键的count设置默认值0 Out[7]:0
上一篇