从类调用时,Python描述符返回自身不是值

时间:2014-02-26 19:59:09

标签: python descriptor

我想从实例和类中访问无法重新分配的属性。由于元类,我有“防止重新分配”的部分。但是,现在无法从类中读取该属性。如何做到这一点。

有这个:

class Meta(type):
    def __setattr__(cls, attr, val):
        if attr =="frozen":
            print "You can't unfreeze the frozen"
        else:
            cls.name = val


class Fixed(object):
    __metaclass__ = Meta
    frzn = 'I AM AWESOME'
    def holdset(_,val):
        _.frzn = _.frzn
        print "frozen is frozen not setting to ", val

    def get(_):
        return _.frzn
    frozen = property(fset=holdset,fget=get)

致电

print Fixed.frozen
print Fixed().frozen

给出

<property object at 0x106dbeba8>
I AM AWESOME

为什么不给它一样?如何让它给出相同的效果?

2 个答案:

答案 0 :(得分:1)

property通常只适用于某个实例。要使属性也适用于类,您需要创建自己的描述符:

class ClassAndInstanceProperty(object):
    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:
            obj = objtype
        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__)

上述与常规property之间的唯一区别在于__get__方法;一个普通的property对象(在C中)相当于:

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)

e.g。在类上,描述符返回self,而我的版本在这种情况下将obj设置为objtype

另请注意,在处理实例时,描述符__set__方法仅 Fixed.frozen = 'something'不会调用描述符__set__,只会调用Fixed().frozen = 'something'。您的元类__setattr__会截取类的属性赋值。

您还可以在元类上放置一个描述符对象,然后有机会让它__set__在类本身上调用属性赋值。

答案 1 :(得分:1)

按照惯例,Python描述符在未使用实例调用时返回自身。属性只是描述符的快捷方式,为此,您需要实现自己的描述符。以下应该做你想要的,而不需要元类:

class Frozen(object):
    def __init__(self, fixed_value):
        self.fixed_value = fixed_value

    def __get__(self, instance, owner=None):
        return self.fixed_value

    def __set__(self, instance, value):
        print "You can't unfreeze the frozen"


class Fixed(object):
    frzn = Frozen("I AM AWESOME")

您可能还想覆盖作为描述符界面一部分的 delete 方法。有一些很好的文章解释了描述符的确切运作方式。