Python魔法方法(magic method)细解几个常用魔法方法(下)

时间:2024-04-09 11:37:39

接上文,再介绍最后几个常用的魔法方法。

关于__dict__:

先上个例子:

class Test(object):
fly = True def __init__(self, age):
self.age = age

__dict__魔法方法可以被称为系统,他是存储各分层属性的魔法方法。__dict__中,键为属性名,值为属性本身。可以这样理解,在平时我们给类和实例定义的那些属性,都会被存储到__dict__方法中用于读取。而我们平时使用的类似这样的语法Test.fly 其实就是调用了类属性,同样可以写成Test.__dict__['fly']。除了类属性,还有实例属性。当我们用类实例化一个实例,例如上文我们使用p = Test(2)实例化类Test,p也会具有__dict__属性。这里会输出:

{'age': 2}

由上可以发现,python中的属性是进行分层定义的。/object/Test/p这样一层一层下来的。当我们需要调用某个属性的时候,python会一层一层往上面遍历上去。先从实例,然后实例的__class__的__dict__,然后是该类的__base__。这样__dict__一路找上去。如果最后都没有找到,就抛出AttributeError错误。

这里可以延伸一下,没记错的话,我前面有篇文章讲了一个方法__slot__。__slots__方法就是通过限制__dict__,只让类实例初始化__slots__里面定义的属性,而且让实例不再拥有__dict__方法,来达到节约内存的目的。我将会就上面的那个例子重写一下,来说明这个问题。

 class Test(object):
__slots__ = ['age'] fly = True def __init__(self, age):
self.age = age

output:

In [25]: Test.__dict__
Out[25]:
dict_proxy({'__doc__': None,
'__init__': <function __main__.__init__>,
'__module__': '__main__',
'__slots__': ['age'],
'age': <member 'age' of 'Test' objects>,
'fly': True}) In [36]: p.__dict__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-36-3a1cec47d020> in <module>()
----> 1 p.__dict__ AttributeError: 'Test' object has no attribute '__dict__' In [37]: p.age
Out[37]: 3 In [38]: p.fly
Out[38]: True

可以看到,__slots__方法并没有阻止由下至上的属性查找方法,只是不会再允许没有包含在__slots__数组中的属性再被赋值给实例了。但这并不妨碍,继续调用允许访问的属性,以及类属性。

关于__get__, __set__, __del__:

在前面的文章里面我也介绍过这三个魔法方法,虽然一般是用不到的,但是在写库的时候它们有特别的用途。他们是python另外一个协议descriptor的根基。

同一个对象的不同属性之间可能存在依赖关系。当某个属性被修改时,我们希望依赖于该属性的其他属性也同时变化。在这种环境下面__dict__方法就无法办到。因为__dict__方法只能用来存储静态属性。python提供了多种即时生成属性的方法。其中一种就是property。property是特殊的属性。比如我们为上面的例子增加一个property特性,使得他能够动态变化。来看这个例子:

class Test(object):
fly = True def __init__(self, age):
self.age = age def whether_fly(self):
if self.age <= 30:
return True
else:
return False def just_try_try(self, other):
pass whether_fly = property(whether_fly) p = Test(20)
print p.age
print p.whether_fly
p.age = 40
print p.age
print p.whether_fly

output:

20
True
40
False

可以看到 我们可以使用这种手段,动态修改属性值。property有四个参数。前三个参数为函数,分别用于处理查询特性、修改特性、删除特性。最后一个参数为特性的文档,可以为一个字符串,起说明作用。这里我只是要到了第一个参数,查询的时候动态修改他的返回值,而第二个参数是在修改值的时候就会体现出来。

Reference:

http://www.cnblogs.com/vamei/archive/2012/12/11/2772448.html