简体   繁体   English

为什么在描述符类的__get__中需要“if instance is None”?

[英]why do you need “if instance is None” in __get__ of a descriptor class?

I get the following example from Effective Python item 31: 我从Effective Python第31项获得以下示例:

from weakref import WeakKeyDictionary
class Grade(object):
    def __init__(self):
        self._values = WeakKeyDictionary()
    def __get__(self, instance, instance_type):
        if instance is None: return self
        return self._values.get(instance, 0)

    def __set__(self, instance, value):
        if not (0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100')
        self._values[instance] = value


# Example 16
class Exam(object):
    math_grade = Grade()
    writing_grade = Grade()
    science_grade = Grade()

first_exam = Exam()
first_exam.writing_grade = 82
second_exam = Exam()
second_exam.writing_grade = 75
print('First ', first_exam.writing_grade, 'is right')
print('Second', second_exam.writing_grade, 'is right')

I can't think of any reason to have if instance is None: return self in __get__ . if instance is None: return self我想不出任何理由if instance is None: return self__get__ if instance is None: return self How can an Exam (or other potential classes using Grade ) instance be None ? Exam (或使用Grade其他潜在课程)实例如何才能成为None

Python will pass in None for the instance when accessing the descriptor on the class. 在访问类的描述符时,Python将为实例传递None

By returning self in that case you can access the descriptor object on the class without having to bypass the protocol (by accessing ClassObj.__dict__['name_of_descriptor'] ). 通过在这种情况下返回self ,您可以访问类上的描述符对象,而无需绕过协议(通过访问ClassObj.__dict__['name_of_descriptor'] )。

>>> class DemoDescriptor:
...     def __get__(self, instance, type_):
...         if instance is None:
...             print('Accessing descriptor on the class')
...             return self
...         print('Accessing descriptor on the instance')
...         return 'Descriptor value for instance {!r}'.format(instance)
... 
>>> class DemoClass(object):
...     foo = DemoDescriptor()
... 
>>> DemoClass.foo  # on the class
Accessing descriptor on the class
<__main__.DemoDescriptor object at 0x1041d3c50>
>>> DemoClass.__dict__['foo']  # bypassing the descriptor protocol
<__main__.DemoDescriptor object at 0x1041d3c50>
>>> DemoClass().foo  # on the instance
Accessing descriptor on the instance
'Descriptor value for instance <__main__.DemoClass object at 0x1041d3438>'

This is how the __get__ method implementations for function and property objects work too. 这也是functionproperty对象的__get__方法实现的工作方式。

For your specific case, each of Exam.math_grade , Exam.writing_grade or Exam.science_grade will call Grade.__get__ , passing in None for the instance, and Exam for the instance_type . 对于您的具体情况, Exam.math_gradeExam.writing_gradeExam.science_grade每一个都将调用Grade.__get__ ,为实例传递None ,并为instance_type传递Exam

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM