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

时间:2010-09-09 23:20:17

标签: python properties

如果我有这个:

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

f = foo()

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

编辑添加:我想要做的是编写一个迭代f成员的函数并对它们做一些事情(不重要)。属性让我失望,因为只需在getattr()中命名它们就会调用它们的__get __()方法。

6 个答案:

答案 0 :(得分:35)

get_dict_attr(下方)在给定对象的attr中查找__dict__,并在其中返回相关值。如果attr不是__dict__中的关键字,则会搜索对象的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>

您认为barFoo.__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)被调用。

详细解释here

答案 1 :(得分:1)

在你的情况下,

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

您可以通过return 0访问其getter方法(fget),如下所示:

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

请注意,您必须将实例f提供给fget(),因为它是一种实例方法(非静态),您可以通过__class__访问它。

答案 2 :(得分:1)

我遇到了类似的情况,其他答案都没有帮助我,所以这是另一种方法。

我的情况略有不同,因为我不是只有一个@property,而是混合了一个自定义装饰器,它为包装方法添加了属性。所以通常我会有这样的事情:

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

我的@my_decorator会让我访问self.bar.my_attribute,其中包含我需要访问的某些数据。这对于函数和方法很有用,但是在尝试将它与@property混合时遇到了麻烦,因为该属性隐藏了对方法的引用(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

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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))

答案 5 :(得分:-1)

我会说忽略其他答案,因为它们很糟糕。

您可以通过foo.bar

获取对该属性的引用

关于你试图对f成员进行迭代的内容,请参阅下面的具体内容。

答案很长:你必须要了解的是Python中的方法不属于实例,而是类对象的属性。例如,

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

如果您致电foo.bar(),Python首先会检查foo是否有bar(它没有),然后检查Foo是否bar它确实如此。然后,Python将foo.bar“绑定”到Foo.bar(foo),并调用它。

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