0

我有这个

#!/usr/bin/env python

import math
class myclass(object):

    def __init__(self,radius):
            self.radius = radius
    @property
    def area(self):
            print myclass.area,  type(myclass.area)
            return math.pi * ( self.radius ** 2)

    @area.setter
    def area(self,value):
           print myclass.area, type(myclass.area)
           pass

    @area.deleter
    def area(self):
           print myclass.area, type(myclass.area)        
           del myclass.area                


if __name__ == '__main__':

    c = myclass(5.4)
    c.area
    c.area = 65
    del c.area                                  

这给出了:

$ ./propertytest.py 
<property object at 0x7ff0426ac0a8> <type 'property'>
<property object at 0x7ff0426ac0a8> <type 'property'>
<property object at 0x7ff0426ac0a8> <type 'property'>

问题:

查看属性对象area的访问方式:c.area. area出现在点运算符的右侧。属性对象使用哪种特殊方法将类实例对象与正确的实例方法绑定并计算结果?属性如何运作?

4

2 回答 2

4

属性是描述符。描述符是具有__get__,__set__和/或__delete__方法的类的实例。每当 python 执行getattr, setattranddelattr时,如果实例没有所述属性,并且在类中有一个具有该名称的属性,并且具有匹配的魔术方法,则调用魔术方法而不是读取/写入/删除属性。

Python 文档提供了有关描述符的更多信息,并且还具有内置property类型的纯 Python 模拟:

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
于 2013-08-20T14:46:54.573 回答
1

为了使上面发生的事情更加明确,让我们摆脱装饰器语法糖:

import math
class myclass(object):

    def __init__(self,radius):
            self.radius = radius

    def getter(self):
            print myclass.area,  type(myclass.area)
            return math.pi * ( self.radius ** 2)

    # create a property object with "getter" as the getter, assigned to "area"
    area = property(getter) 

    # area.__get__ is now a method that wraps "getter"



    def setter(self,value):
           print myclass.area, type(myclass.area)
           pass

    # create a copy of the "area" object with "setter" as a setter, assign back to "area"
    area = area.setter(setter) 

    # area.__set__ is now a method that wraps "setter"



    def deleter(self):
           print myclass.area, type(myclass.area)        
           del myclass.area  

    # create a copy of the "area" object with "deleter" as a deleter, assign back to "area"
    area = area.deleter(deleter)

    # area.__delete__ is now a method that wraps "deleter"
于 2013-08-20T15:03:02.000 回答