[英]Why does this class descriptor __get__ method return self?
I am working through the O Reilley Python Cookbook and I have a question about the following code:我正在阅读O Reilley Python Cookbook ,我对以下代码有疑问:
class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError('Expected ' + str(self.expected_type))
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
# Class decorator that applies it to selected attributes
def typeassert(**kwargs):
def decorate(cls):
for name, expected_type in kwargs.items():
# Attach a Typed descriptor to the class
setattr(cls, name, Typed(name, expected_type))
return cls
return decorate
# Example use
@typeassert(name=str, shares=int, price=float)
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
if __name__ == '__main__':
s = Stock('ACME', 100, 490.1)
print(s.name, s.shares, s.price)
s.shares = 50
try:
s.shares = 'a lot'
except TypeError as e:
print(e)
Im confused about the part:我对这部分感到困惑:
def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]
if instance is not set (ie None) then it says return 'self', given that self represents the class descriptor what exactly is returned?如果未设置实例(即无),则它说返回“self”,鉴于 self 代表类描述符,究竟返回了什么?
then it says return 'self', given that self represents the class descriptor what exactly is returned?
然后它说返回'self',鉴于self代表类描述符,究竟返回什么?
You've just answered your own question: it returns the descriptor object itself.您刚刚回答了自己的问题:它返回描述符对象本身。
So when the descriptor is accessed on the class, instance
will be None
, and in this case it just returns the descriptor.因此,当在类上访问描述符时,
instance
将为None
,在这种情况下它只返回描述符。 Consider the example of property
re-implemented in Python from the Descriptor HOWTO:考虑描述符 HOWTO 中在 Python 中重新实现的
property
示例:
In [5]: 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:
...: print('obj is None in Property.__get__')
...: 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__)
...:
Then:然后:
In [6]: class Foo:
...: @Property
...: def bar(self):
...: return 42
...:
In [7]: Foo.bar
obj is None in Property.__get__
Out[7]: <__main__.Property at 0x1044d02b0>
In [8]: Foo().bar
Out[8]: 42
Yes, it returns the descriptor instance.是的,它返回描述符实例。
The second argument (the first after self
) for __get__
is either the instance on which the descriptor is looked up - or None
if it's looked up on the class. __get__
的第二个参数( self
之后的第一个)要么是在其上查找描述符的实例,要么是None
如果在类上查找)。
So in the given case it returns the descriptor in case you look up the descriptor on the class.因此,在给定的情况下,它会返回描述符,以防您在类上查找描述符。
Just to illustrate that:只是为了说明:
class Descriptor:
def __get__(self, instance, owner):
if instance is None:
return self
return 10
class Test:
test = Descriptor()
>>> Test.test
<__main__.Descriptor at 0x2769b7d44c8>
>>> Test.__dict__['test']
<__main__.Descriptor at 0x2769b7d44c8>
Now, if it didn't use return self
there it would look like this:现在,如果它没有使用
return self
,它看起来像这样:
class Descriptor:
def __get__(self, instance, owner):
return 10
class Test:
test = Descriptor()
>>> Test.test
10
>>> Test.__dict__['test']
<__main__.Descriptor at 0x2769b7de208>
The reason this return self
is often done is because it allows to get the descriptor instance without having to search in __dict__
(potentially in all superclasses).经常执行此
return self
的原因是因为它允许获取描述符实例而无需在__dict__
搜索(可能在所有超类中)。 In most cases it simply makes no sense to do anything when the property is looked up on the class, so returning the instance is a good idea.在大多数情况下,在类中查找属性时做任何事情都没有意义,因此返回实例是一个好主意。
It's also what the built-in property
does (and also the function-descriptor):这也是内置
property
作用(以及函数描述符):
class A:
@property
def testproperty(self):
return 10
def testmethod(self):
return 10
>>> A.testproperty
<property at 0x2769b7db9a8>
>>> A.testproperty.__get__(None, A)
<property at 0x2769b7db9a8>
>>> A.testmethod
<function __main__.A.testmethod(self)>
>>> A.testmethod.__get__(None, A)
<function __main__.A.testmethod(self)>
In those cases where something meaningful should happen when the attribute is looked up on the class (for example the built-in staticmethod
and classmethod
descriptors) then that's of course different and self
should not be returned there!在那些在类上查找属性时应该发生有意义的事情的情况下(例如内置的
staticmethod
和classmethod
描述符),那当然是不同的,不应在那里返回self
!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.