Chinaunix首页 | 论坛 | 博客
  • 博客访问: 469515
  • 博文数量: 111
  • 博客积分: 2332
  • 博客等级: 大尉
  • 技术积分: 1187
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-29 11:22
文章分类

全部博文(111)

文章存档

2013年(9)

2012年(28)

2011年(17)

2010年(28)

2009年(29)

我的朋友

分类: Python/Ruby

2010-01-21 15:35:25

最近看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
>>>>>>>>>

阅读(971) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~