最近看django源码的时候发现了python的descriptor,以前从来没有涉及过,(python的基础真是差啊,我),所以来学习一下。
参考了:
http://blog.chinaunix.net/u/23216/showart_189009.html
descriptor实际上就是一个类的属性,只不过这个属性定义了__get__,__set__,__del__这三个方法中的一个或者多个(最少要有__get__),然后当这个类的对象调用这个属性的时候就会相应的调用__get__或者__set__或者__del__。只定义了__get__方法的descriptor是non-data descriptor,定义了__set__的是data-descriptor。
descriptor只能被一个新式的类或者类对象调用。(新式的类就是从objct或者type继承的类)。
类和类的对象都有__dict__,调用类对象的属性时:对于obj.x,优先查找obj.__dict__["x"],如果找不到,再查找class.__dict__["x"];调用类的属性时;对于class.x,直接查找class.__dict__["x"];obj.__dict__与class.__dict__可以拥有同名的属性;obj.x=10,将无条件的更新obj.__dict__;class.x=10,将无条件的更新class.__dict__。这里在掉用__dict__['x']的时候按照以下优先级:
data descriptor高于obj.__dict__['x']高于non-data descriptor。
我自己做了一些实验,感觉和javaeye以及chinaunix里面的两篇文章多少都有一些不一样(虽然这两篇文章好些写的一些细节也不一样)。
代码如下:(data-descriptor)
#coding:utf-8
class AA(object):
def __init__(self):
self.value = 25
def __get__(self, ownerobj, ownerclass):
print "it is in ", ownerobj, "get"
print "value is ", str(self.value)
return self.value
def __set__(self, ownerobj, value):
print "it is in ", ownerobj, "set"
print "original value is ", self.value
print "now value is ", value
self.value = value
def __delete__(self, ownerobj):
pass
class CC(object):
x = 5
aobj = AA()
c = CC()
CC.aobj
c.aobj
print ">>>"*3
c.aobj = 15 #因为是data descriptor,而且c.__dict__中没有aobj这个键名,所以这里调用的是CC.__dict__['aobj'].__set__
CC.aobj #这里调用的是CC.__dict__['aobj'].__get__
c.aobj #因为c.__dict__中没有aobj这个键名,所以这里调用的是CC.__dict__['aobj'].__get__
print ">>>"*3 #注意:感觉应该调用的是descriptor,但实际上是调用的是__dict__,不知道为什么。
CC.aobj = 35 #这里好像是调用的CC.__dict__['aobj'],而不是descriptor,不知道为什么。
CC.aobj #这里调用的是CC.__dict__['aobj'],值是35。
c.aobj #因为c.__dict__中没有aobj这个键名,所以这里调用的是CC.__dict__['aobj'].,值是35。
|
运行结果为:
it is in None get
value is 25
it is in <__main__.CC object at 0xb76dc48c> get
value is 25
>>>>>>>>>
it is in <__main__.CC object at 0xb76dc48c> set
original value is 25
now value is 15
it is in None get
value is 15
it is in <__main__.CC object at 0xb76dc48c> get
value is 15
>>>>>>>>>
non-data descriptor代码为:#coding:utf-8
class AA(object):
def __init__(self):
self.value = 25
def __get__(self, ownerobj, ownerclass):
print "it is in ", ownerobj, "get"
print "value is ", str(self.value)
return self.value
# def __set__(self, ownerobj, value):
# print "it is in ", ownerobj, "set"
# print "original value is ", self.value
# print "now value is ", value
# self.value = value
# def __delete__(self, ownerobj):
# pass
class CC(object):
x = 5
aobj = AA()
c = CC()
CC.aobj
c.aobj
print ">>>"*3
c.aobj = 15 #因为是non-data descriptor直接设置了c.__dict__
CC.aobj #调用的是CC.__dict__['aobj'].__get__,他返回的是关于CC类的,而不是上面对c设置的15
c.aobj #因为是non-data descriptor,他调用的是c.__dict__中的值,所以没有print行为发生
print ">>>"*3
CC.aobj = 35 #设置的是CC.__dict__中的值
CC.aobj #在这里是从CC.__dict__中直接取的属性值,所以没有print行为发生他的值是刚才设置的35
c.aobj #因为是non-data descriptor,所以这里调用的是c.__dict__中的值,没有print行为发生。其值上面c.aobj=15设置的15
|
运行结果为:
it is in None get
value is 25
it is in <__main__.CC object at 0xb782038c> get
value is 25
>>>>>>>>>
it is in None get
value is 25
>>>>>>>>>
阅读(1029) | 评论(0) | 转发(0) |