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
答案 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)
调用的细节取决于
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 = 2
或del cls.prop
将直接覆盖或删除属性对象,而无需调用__set__
或__delete__
。