在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__中。