我可以获得对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_attr
, obj.__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>
您可以通过传递对象f
和f
的类作为参数来调用该方法:
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
请注意,您必须将实例f
给fget()
因为它是一个实例方法(非静态),您可以通过__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
并返回它。