在Python中使用属性时Class.foo和instance.foo的不同行为
我的问题是: 当我使用“属性”控制一个变量的访问时在Python中使用属性时Class.foo和instance.foo的不同行为,python,python-3.x,python-2.7,Python,Python 3.x,Python 2.7,我的问题是: 当我使用“属性”控制一个变量的访问时 instance.var将正确返回实际值, 而Class.var将返回属性对象本身(例如位于0x7fc5215ac788的属性对象) 但是,当我使用等效方法(例如描述符)并重写\uuuu get\uuuu和\uuu set\uuu方法时, instance.var和Class.var都可以返回实际值,而不是对象本身 那么为什么他们的行为如此不同呢 我猜这是因为my描述符中实现的一些默认函数具有魔力,那么它们是什么呢 更新: 出现上述问题的原因
instance.var
将正确返回实际值,
而Class.var
将返回属性对象本身(例如位于0x7fc5215ac788的属性对象)
但是,当我使用等效方法(例如描述符)并重写\uuuu get\uuuu
和\uuu set\uuu
方法时,
instance.var
和Class.var
都可以返回实际值,而不是对象本身
那么为什么他们的行为如此不同呢
我猜这是因为my描述符中实现的一些默认函数具有魔力,那么它们是什么呢
更新:
出现上述问题的原因是,在属性
中实现的\uuuu get\uuuu
函数将确定它是由实例调用还是由类调用,当它由类调用时,它将返回对象本身(即self)
但是由于\uuuu set\uuu
函数没有类型
或cls
参数,并且根据我的测试,\uu set\uuu
函数无法捕获Class.var=5
。
因此,我想知道我们可以使用什么钩子来定制类变量级别分配class.var=value
?当您执行MyClass时。某些描述符
,显然没有实例可以传递给描述符,因此它是用obj=None
调用的:
##### Case 1, use property #####
class Case1:
# ignore getter and setter for property
var = property(getter, setter, None, None)
##### Case 2, use equivalent methods ####
class Descriptor:
def __get__(self, obj, type=None):
return None
def __set__(self, obj, val):
pass
class Case2:
var = Descriptor()
这就是所有涉及的“魔力”
现在,如果您想知道为什么这不是默认值:有一些用例可以为在类上查找的描述符返回其他内容—例如方法(是的,Python函数是描述符—它们的\uuuuu get\uuuu
方法返回方法
对象,该对象实际上是实例周围的可调用包装器(如果有的话),类别及功能):
Foo.meth=lambda self:42
>>>氟甲基苯丙胺
>>>Foo().meth
>>>Foo.meth(Foo())
42
btw,我发现Python确实有很多“implit”行为,例如,像“instance.var”如何涉及“\u getattribute\uu”和最后涉及“\u getattr\uu”,在很多书中几乎没有提到。我想知道是否有一些很好的材料涵盖了这类主题?关于什么?就我而言,这是相当明确的,特别是因为Python是为数不多的公开暴露其对象模型内部并让您与之挂钩的OOPL之一。哦,是的:\uuuu getattr\uuuu
仅在实现时调用(在对象
中没有默认实现),并且作为最后手段,如果之前没有解决该属性。根据我的测试,类变量级别分配class.var=value
不能被\uuuu set\uuuu
函数捕获,即使var
是描述符,因为它没有type
或cls
参数。那么你知道我可以用什么钩子来进行这种定制吗?
>>> class Desc(object):
... def __get__(self, obj, cls=None):
... print "obj : {} - cls : {}".format(obj, cls)
... return 42
...
>>> class Foo(object):
... bar = Desc()
...
>>> Foo.bar
obj : None - cls : <class '__main__.Foo'>
42
>>> Foo().bar
obj : <__main__.Foo object at 0x7fd285cf4a90> - cls : <class '__main__.Foo'>
42
>>>
>>> class Desc2(object):
... def __get__(self, obj, cls=None):
... if obj is None:
... return self
... return 42
...
>>> Foo.baaz = Desc2()
>>> Foo.baaz
<__main__.Desc2 object at 0x7fd285cf4b10>
>>> Foo().baaz
42
>>>
>>> Foo.meth = lambda self: 42
>>> Foo.meth
<unbound method Foo.<lambda>>
>>> Foo().meth
<bound method Foo.<lambda> of <__main__.Foo object at 0x7fd285cf4bd0>>
>>> Foo.meth(Foo())
42