可以使用getattr(obj,attr)或inspect.getmembers(obj)来获取对象属性,然后按名称进行过滤:

import inspect

class Foo(object):

    def __init__(self):

        self.a = 100

    def method(self): pass

foo = Foo()
method_by_getattr = getattr(foo, 'method')

foo_members = inspect.getmembers(foo)
method_by_inspect = [member[1] for member in foo_members
                        if member[0] == "method"][0]

print (id(method_by_getattr), method_by_getattr, type(method_by_getattr))
print (id(method_by_inspect), method_by_inspect, type(method_by_inspect))

a_by_getattr = getattr(foo, "a")
a_by_inspect = [member[1] for member in foo_members
                        if member[0] == "a"][0]

print (id(a_by_getattr), a_by_getattr, type(a_by_getattr))
print (id(a_by_inspect), a_by_inspect, type(a_by_inspect))

# (38842160L, <bound method Foo.method of <__main__.Foo object at 0x00000000025EF390>>, <type 'instancemethod'>)
# (39673576L, <bound method Foo.method of <__main__.Foo object at 0x00000000025EF390>>, <type 'instancemethod'>)
# (34072832L, 100, <type 'int'>)
# (34072832L, 100, <type 'int'>)

对于'a'属性,getattr和inspect.getmembers返回相同的对象。但是对于方法“方法”,它们将返回不同的对象(可以通过不同的ID看到)。

为什么会这样呢?

最佳答案

我对您的示例进行了一些重组,以更好地说明我将用来解释行为的变体

With temporary variables

import inspect

def print_id(obj):
    print "{} => {}".format(id(obj), obj)

def getmember(obj, name):
    #members = dict(inspect.getmembers(obj))
    #return members[name]
    return [member
            for _name, member in inspect.getmembers(obj)
            if name == _name][0]

class Foo(object):
    def bar(self): pass

foo = Foo()

m1 = foo.bar
m2 = getattr(foo, 'bar')
m3 = getmember(foo, 'bar')

print_id(m1)
print_id(m2)
print_id(m3)

但是,如果您在REPL中检查对象,则代码的基本结构可能如下所示:

Without temporary variables
#...
foo = Foo()

print_id(foo.bar)
print_id(getattr(foo, 'bar'))
print_id(getmember(foo, 'bar'))
id()函数基本上返回对象的内存地址。也就是说,在整个程序运行期间创建的所有对象之间,唯一的标识不是唯一的。它仅在给定时间点的过程中存在的所有对象之间是唯一的。

符合两个示例之间的差异的解释是,以三种方式中的任何一种方式解决foo.bar每次都会为提供一个新对象。在第一个示例中,这些对象存储在临时变量中,因此所有这三个对象必须位于不同的内存地址。

在第二个示例中,绑定(bind)方法对象在打印出来之后不再需要; Python引用计数GC将释放其内存。这意味着下一次创建绑定(bind)方法对象时,它是一个新对象,碰巧在与上一个对象相同的内存地址处创建了该对象。这就是为什么您似乎多次获得同一对象的原因。

您总是可以得到一个新的绑定(bind)方法对象:
>>> foo.bar == foo.bar
True
>>> foo.bar is foo.bar
False

关于python - getattr vs. inspect.getmembers,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12848507/

10-10 02:46