我可以获得对Python属性的引用吗?

如果我有这个:

class foo(object): @property def bar(self): return 0 f = foo() 

如果没有实际调用方法,如何获得对f.bar的引用?

编辑添加:我想要做的是写一个函数,迭代f的成员,并与他们做什么(什么是不重要的)。 属性让我跳了起来,因为只是在getattr()中命名它们就会调用它们的__get __()方法。

get_dict_attr (下面)在给定对象的__dict__查找attr ,并返回关联值(如果存在)。 如果attr不是__dict__的关键字,则search该对象的MRO的__dict__ 。 如果找不到密钥,则会引发AttributeError

 def get_dict_attr(obj, attr): for obj in [obj] + obj.__class__.mro(): if attr in obj.__dict__: return obj.__dict__[attr] raise AttributeError 

例如,

 class Foo(object): x=1 def bar(self): pass @property def baz(self): return 0 foo=Foo() print(get_dict_attr(foo,'x')) # 1 print(get_dict_attr(foo,'bar')) # <unbound method Foo.bar> print(get_dict_attr(foo,'baz')) # <property object at 0xb77c0dc4> print(get_dict_attr(foo,'y')) # AttributeError 

请注意,这与属性查找的常规规则非常不同。 首先, obj.__class__.__dict__数据描述符(带有__get____set__方法的描述符)通常优先于obj.__dict__值。 在get_dict_attrobj.__dict__具有优先权。

get_dict_attr不会尝试调用__getattr__

最后, get_dict_attr只能用于obj ,它们是新风格类的实例。

不过,我希望这是一些帮助。


 class Foo(object): @property def bar(self): return 0 f = Foo() 

这引用了属性bar

 print(Foo.bar) # <property object at 0xb76d1d9c> 

你看吧是Foo.__dict__一个关键Foo.__dict__

 print(Foo.__dict__['bar']) # <property object at 0xb775dbbc> 

所有属性都是描述符,这意味着它有一个__get__方法:

 print(Foo.bar.__get__) # <method-wrapper '__get__' of property object at 0xb76d7d74> 

您可以通过传递对象ff的类作为参数来调用该方法:

 print(Foo.bar.__get__(f,Foo)) # 0 

我喜欢以下图表。 垂直线显示对象和对象的类之间的关系。

当你有这种情况:

  Foo B | Foo.__dict__={'bar':b} | B.__dict__={'__get__':...} | \ | f `--------> b 

f.bar导致b.__get__(f,Foo)被调用。

这在这里详细解释。

在你的情况下,

 class foo(object): @property def bar(self): return 0 f = foo() 

您可以通过类的字典访问该属性:

 f.__class__.__dict__['bar'] => <property at 0x4920c28> 

正如你所看到的,这是一个property实例。

 isinstance(f.__class__.__dict__['bar'], property) => True 

你可以像这样通过fget访问它的getter方法(它会return 0 ):

 f.__class__.__dict__['bar'].fget(f) => 0 

请注意,您必须将实例ffget()因为它是一个实例方法(非静态),您可以通过__class__访问它。

我碰到类似的情况,没有其他答案帮助我,所以这里有一个替代方法。

我的情况稍有不同,因为我不是只拥有一个@property ,而是在一个定制的装饰器中混合,这个装饰器为包装的方法添加了属性。 所以通常我会有这样的东西:

 class Foo: @my_decorator def bar(self): return do_stuff() # Pretend this is non-trivial 

然后,我的@my_decorator会让我访问self.bar.my_attribute ,它有一些我需要访问的数据。 这对于函数和方法非常适用,但是当我试图将它与self.bar.my_attribute混合使用时遇到了一些问题,因为属性隐藏了对方法的引用( self.bar.my_attribute失败,因为self.bar返回方法的返回值,没有我想要的my_attribute )。

我会使用@property作为外部装饰器,如下所示:

 class Foo: @property @my_decorator def bar(self): return do_stuff() # Pretend this is non-trivial 

然后解决scheme是访问my_attribute作为Foo.bar.fget.my_attribute (这里重要的细节是从类访问属性返回属性对象,而从实例访问属性只是调用该方法并返回值,无需访问原始方法的参考)。

TL; DR:如果您需要提供您的@property的方法的引用,则需要使用YourClassName.your_property.fget

有一件事你应该知道的是,数据描述符(即属性)只适用于(新风格)的类(见http://docs.python.org/reference/datamodel.html#implementing-descriptors )。 将它们复制到对象将不会在该对象上创build属性。 您需要将它们复制到(新式)类才能生效。

 class A: prop = property(lambda self: 'get', lambda self, x: print('set', x)) setter = A.prop.fset getter = A.prop.fget my_a = A() setter(my_a, 5) print(getter(my_a)) 

我会说忽略其他答案,因为他们是不好的。

您可以通过foo.bar获得对该属性的foo.bar

至于你想要做什么迭代f的成员,请参阅下面的具体细节。

长的回答:你必须明白的是,Python中的方法不属于实例,而是类对象的属性。 例如,

 class Foo: def bar(self): pass foo = Foo() 

如果你调用foo.bar() ,Python首先检查foo是否有bar (不),然后检查Foo是否有bar ,它是foo.bar() 。 然后Python将foo.bar “绑定”到Foo.bar(foo) ,然后调用它。

属性也是如此。 我不知道确切的过程(我想它在实现中有所不同),但是本质上Python寻找foo.bar ,然后Foo.bar看到它是一个属性,所以评估它的getter并返回它。