在Python一些类中,通常能看到用双画线“__”开头和结尾的属性和方法,总归为特殊属性。他和我们自己所写的非"__"开头和结尾的属性方法有一些区别。


1,__dict__
 
>>> class test(object):


print "这是个测试"




这是个测试


>>> t = test()
 
>>> dir(t)
 
['__class__', '__delattr__', ' 
 __dict__ 
 ', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']


dir()能够查看类的属性和方法,所以在列出的结果中,都是以 “__”开头和结尾的,这些都是所谓的特殊属性和方法。


>>> class GoTest(object):
 
 gogo = "This is Test"
 
 
 
 
 
 
>>> GoTest. 
 __dict__
 
dict_proxy({ 
 'gogo': 'This is Test' 
 , '__dict__': <attribute '__dict__' of 'GoTest' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'GoTest' objects>, '__doc__': None})


从现实的结果中可以发现,有一个键“gogo ”,它是这个类的属性;其值就是类属性的数据。


>>> GoTest.__dict__['gogo']
 
'This is Test'
 
>>> GoTest.gogo
 
'This is Test'


GoTest.__dict__['gogo']意思是访问类属性,这是看到上述结果为字典类型而想到的;另外一个我们熟悉的方式就是通过点号,也一样能够实现同样的效果。


2,__slots__


优化内存使用。在某些程序当作,优化内存是非常有用和必要的。

>>> class TestSlots(object):
 
  
 __slots__ 
  = ("hello","world")
 
 
 
 
>>> dir(TestSlots)
 
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'hello', 'world']

看看dir()的结果,没有有__dict__属性了;

>>> TestSlots.__slots__
 
('hello', 'world')
 
>>> t = TestSlots()
 
>>> t.__slots__
 
('hello', 'world')


实例化之后,实例的__slots__与类的完全一样


>>> t.hello = "zhangsan"
 
>>> TestSlots.hello = "lisi"
 
>>> t.hello = "zhangsan"
 
 
 
 
Traceback (most recent call last):
 
 File "<pyshell#34>", line 1, in <module>
 
 t.hello = "zhangsan"
 
AttributeError: 'TestSlots' object attribute 'hello' is read-only


报错信息中显示tree这个属性是只读的,不能修改。

>>> class TestSlots1(object):
 
  
 __slots__ 
  = ("hello","world")
 
 
 
 
>>> t = TestSlots1()
 
>>> t.world = "gaga"
 
>>> t.world
 
'gaga'
 
>>> TestSlots1.world
 
<member 'world' of 'TestSlots1' objects>


实例属性的值并没有传回到类属性,你也可以理解为新建立了一个同名的实例属性。


__slots__已经把实例属性牢牢地管控了起来,但更本质的是优化了内存。这种优化在有大量实例的情况下效果才显著。


3,__getattr__、__setattr__等


__setattr__(self,name,value):如果要给name赋值,就调用这个方法。


__getattr__(self,name):如果name被访问,同时它不存在,此方法被调用。


__getattribute__(self,name):当name被访问时自动被调用(注意:这个仅能用于新式类),无论name是否存在,都要被调用。


__delattr__(self,name):如果要删除name,这个方法就被调用。

>>> class A(object):
 
 print "111"
 
 
 
 
111
 
>>> a = A()
 
>>> a.x
 
 
 
 
Traceback (most recent call last):
 
 File "<pyshell#59>", line 1, in <module>
 
 a.x
 
AttributeError: 'A' object has no attribute 'x'


x不是实例的成员(“成员”笼统指类的属性和方法),用a.x访问一定会报错

>>> class A(object):
 
 def 
  __getattr__ 
 (self, name):
 
 print "You use getattr"
 
 def  
 __setattr__ 
 (self, name, value):
 
 print "You use setattr"
 
 self.__dict__[name] = value
 
 
 
 
 
 
>>> a = A()
 
>>> a.x
 
You use getattr


依然调用了不存在的属性a.x,按照正常例子是要报错的。但是,由于在这里使用了__getattr__(self,name)方法,当发现x不存在于对象的__dict__中时,就调用了__getattr__“拦截成员”。

>>> a.x = "hello"
 
You use setattr
 
>>> a.x
 
'hello'

给对象的属性赋值时,调用了__setattr__(self,name,value)方法,这个方法中有一句self.__dict__[name]=value,通过这个语句,就将属性和数据保存到了对象的__dict__中。