Python 为什么这个类描述符get方法返回self?
我正在阅读O Reilley Python食谱,我对以下代码有一个问题:Python 为什么这个类描述符get方法返回self?,python,python-3.x,python-descriptors,Python,Python 3.x,Python Descriptors,我正在阅读O Reilley Python食谱,我对以下代码有一个问题: 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
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)
我对这个部分感到困惑:
def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]
如果未设置实例(即无),那么它会说返回“self”,因为self表示类描述符,那么返回的究竟是什么
然后它说返回“self”,因为self代表类
描述符返回的是什么
您刚刚回答了自己的问题:它返回描述符对象本身
因此,当在类上访问描述符时,实例
将是无
,在这种情况下,它只返回描述符。从代码描述符HOWTO:中,考虑Python中实现的<代码>属性
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__)
...:
然后:
[6]中的:Foo类:
…:@属性
…:定义栏(自身):
…:返回42
...:
在[7]中:Foo.bar
obj不在属性中。\u__
出[7]:
在[8]中:Foo().bar
Out[8]:42
是,它返回描述符实例
\uuuu get\uuuu
的第二个参数(self之后的第一个参数)要么是在其上查找描述符的实例,要么是在类上查找描述符的实例
因此,在给定的情况下,如果您在类上查找描述符,它将返回描述符
为了说明这一点:
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>
之所以经常执行此返回self
,是因为它允许获取描述符实例,而无需在中搜索(可能在所有超类中)。在大多数情况下,在类上查找属性时执行任何操作都没有意义,因此返回实例是一个好主意
这也是内置的属性
的作用(以及函数描述符):
A类:
@财产
def testproperty(自):
返回10
def测试方法(自我):
返回10
>>>A.testproperty
>>>A.testproperty.\uuuuu获取\uuuuu(无,A)
>>>测试方法
>>>A.testmethod.\uuuuu获取\uuuuu(无,A)
如果在类上查找属性时发生了有意义的事情(例如内置的staticmethod
和classmethod
描述符),那么这当然是不同的,self
不应该在那里返回 相关的:
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>
class Descriptor:
def __get__(self, instance, owner):
return 10
class Test:
test = Descriptor()
>>> Test.test
10
>>> Test.__dict__['test']
<__main__.Descriptor at 0x2769b7de208>
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)>