Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么这个类描述符get方法返回self?_Python_Python 3.x_Python Descriptors - Fatal编程技术网

Python 为什么这个类描述符get方法返回self?

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

我正在阅读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 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)>