属性的描述符协议实现()

时间:2016-10-09 17:50:39

标签: python

Python descriptor How-To描述了如何根据描述符实现property()。我不明白__get__方法中第一个if-block的原因。 obj None在什么情况下会__get__?应该发生什么呢?为什么__del__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): # =====>>> What's the reason of this if block? <<<===== 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__) 方法没有检查?

代码有点冗长,但提供完整代码而不仅仅是一个片段可能更好。标有可疑行。

Public Function IsNumberXValid(x) As Boolean
   IsNumberXValid = IsNumeric(x) And Math.Cos(x) <> 1
End Function

2 个答案:

答案 0 :(得分:2)

您可以通过制作另一个离开该测试的版本来了解效果。我创建了一个使用您发布的代码的类Property,以及另一个不包含if块的BadProperty。然后我做了这个课:

class Foo(object):
    @Property
    def good(self):
        print("In good getter")
        return "good"

    @good.setter
    def good(self, val):
        print("In good setter")

    @BadProperty
    def bad(self):
        print("In bad getter")
        return "bad"

    @bad.setter
    def bad(self, val):
        print("In bad setter")

在这个例子中可以看到相同点和不同点:

>>> x = Foo()

# same
>>> x.good
In good getter
'good'
>>> x.bad
In bad getter
'bad'
>>> x.good = 2
In good setter
>>> x.bad = 2
In bad setter

# different!
>>> Foo.good
<__main__.Property object at 0x0000000002B71470>
>>> Foo.bad
In bad getter
'bad'

if块的作用是返回原始属性对象本身(如果通过类访问它)。如果没有这个检查,即使通过类访问描述符,也会调用getter。

__set____del__方法不需要这样的检查,因为在类(仅在实例上)上设置/删除属性时根本不调用描述符协议。从文档中可以看出这一点并不完全明显,但__get__the docs__set__ / __del__的描述之间存在差异,其中DEMO 1}}可以获取“所有者类或实例”的属性,但__get__ / __set__仅设置/删除实例上的属性。

答案 1 :(得分:1)

来自descriptor documentation

  

调用的细节取决于obj是对象还是类。

基本上,实例将描述符调用为type(b).__dict__['x'].__get__(b, type(b)),而类将描述符调用为B.__dict__['x'].__get__(None, B)。如果obj is None表示从类中调用了getter,而不是实例。

此机制用于实施classmethods

__set____delete__不检查obj is None,因为它们永远不会像这样被调用。从类中调用时,仅调用__get__。执行cls.prop = 2del cls.prop将直接覆盖或删除属性对象,而无需调用__set____delete__