简体   繁体   English

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

[英]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!在那些在类上查找属性时应该发生有意义的事情的情况下(例如内置的staticmethodclassmethod描述符),那当然是不同的,不应在那里返回self

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 python 描述符 __get__ 方法接受所有者类作为参数? - Why does a python descriptor __get__ method accept the owner class as an arg? 什么时候让描述符的`__get__`方法返回另一个描述符为什么有用? - When any why is it useful to have a descriptor's `__get__` method return another descriptor? 方法的描述符__get__ - Descriptor __get__ from method 为什么类的对象不调用__get__和__set__即描述符方法? - why object of class does not call __get__ and __set__ i.e descriptor methods? 为什么在描述符类的__get__中需要“if instance is None”? - why do you need “if instance is None” in __get__ of a descriptor class? 为什么在 hassattr() 内部调用 Python 中描述符的 __get__ 方法? - Why __get__ method of a descriptor in Python is called inside of hassattr()? 对象类的描述符__class__的__get__没有按预期返回 - __get__ of descriptor __class__ of object class doesn't return as expected python3:使用.__ get __()将类方法绑定到类实例,但是为什么呢? - python3: bind method to class instance with .__get__(), it works but why? 为什么描述符__get__可以访问对象的类型,但__set__没有? - Why does a descriptor __get__ have access to the object's type but __set__ does not? object.__getattribute__ 如何重定向到我的描述符和 __getattr__ 上的 __get__ 方法? - How does object.__getattribute__ redirect to __get__ method on my descriptor and __getattr__?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM