我刚读过about descriptors,并且感到非常无意的是,一个班级的行为可能取决于谁使用它。这两种方法
__get__(self, instance, owner)
__set__(self, instance, value)
正是这样做的。他们进入使用它们的类的实例。这个设计决定的原因是什么?它是如何使用的?
更新:我认为描述符是普通类型。使用它们作为成员类型的类可以通过描述符的副作用轻松地进行操作。这是我的意思的一个例子。为什么Python支持?
class Age(object):
def __init__(value):
self.value = value
def __get__(self, instance, owener):
instance.name = 'You got manipulated'
return self.value
class Person(object):
age = Age(42)
name = 'Peter'
peter = Person()
print(peter.name, 'is', peter.age)
答案 0 :(得分:2)
__get__
和__set__
不会收到有关他们是谁的电话信息。 3个参数是描述符对象本身,正在访问其属性的对象以及对象的类型。
我认为清除它的最佳方法是举个例子。所以,这里有一个:
class Class:
def descriptor(self):
return
foo_instance = Foo()
method_object = foo_instance.descriptor
函数是描述符。当您访问对象的方法时,通过查找实现该方法并调用__get__
的函数来创建方法对象。这里,
method_object = foo_instance.descriptor
调用descriptor.__get__(foo_instance, Foo)
来创建method_object
。 __get__
方法不会收到有关谁调用它的信息,只接收执行其属性访问任务所需的信息。
答案 1 :(得分:1)
描述符用于实现绑定行为;描述符需要一个上下文,它们所依赖的对象。
该对象是传入的instance
对象。
请注意,如果没有描述符,对象上的属性访问将直接作用于对象属性(设置或删除时的实例__dict__
,否则也会搜索类和基类属性。)
描述符允许您完全委托对单独对象的访问,封装获取,设置和删除。但是为了能够这样做,该对象需要访问上下文,即实例。因为获取属性通常也会搜索类及其基础,所以__get__
描述符方法也会传递实例的类(owner
)。
以功能为例。函数也是一个描述符,将它们绑定到实例会产生一个方法。一个类可以有任意数量的实例,但是在创建实例时在所有这些实例上存储绑定方法没有多大意义,这将是浪费。
相反,函数是动态绑定的;你在实例上查找函数名,而不是在类上找到函数,并且通过调用__get__
函数绑定到实例,返回一个方法对象。然后,此方法对象可以在调用时将实例传递给函数,从而生成self
参数。
答案 2 :(得分:1)
运行中的描述符协议的一个示例是绑定方法。当您访问实例方法o.foo
时,您可以立即调用它或将其保存到变量a = o.foo
中。现在,当您致电a(x, y, z)
时,实例o
将作为第一个foo
参数传递给self
:
class C(object):
def foo(self, x, y, z):
print(self, x, y, z)
o = C()
a = o.foo
a(1, 2, 3) # prints <C instance at 0x...> 1 2 3
这是因为函数实现了描述符协议;当你在对象实例上__get__
一个函数时,它返回一个绑定方法,实例绑定到该函数。
如果没有描述符协议可以访问对象实例,上述方法就无法工作。