首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >getattr与inspect.getmembers

getattr与inspect.getmembers
EN

Stack Overflow用户
提问于 2012-10-12 05:05:31
回答 2查看 8.1K关注 0票数 6

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

代码语言:javascript
运行
复制
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返回相同的对象。但是对于方法' method‘,它们返回不同的对象(从不同的id可以看出)。

为何会这样呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-12 06:03:42

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

With temporary variables

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
#...
foo = Foo()

print_id(foo.bar)
print_id(getattr(foo, 'bar'))
print_id(getmember(foo, 'bar'))

id()函数基本上返回对象的内存地址。也就是说,它不是在程序的整个运行时期间创建的所有对象之间唯一的标识。它只在任何给定时间点存在于进程中的所有对象之间是唯一的。

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

在第二个示例中,打印出绑定方法对象后不再需要它;Python引用计数GC将释放其内存。这意味着下一次创建绑定方法对象时,它是一个新对象,恰好在与前一个对象相同的内存地址上创建。这就是为什么看起来你会多次得到同一个对象的原因。

你总是会得到一个新的绑定方法对象,这一点可以简单地展示出来:

代码语言:javascript
运行
复制
>>> foo.bar == foo.bar
True
>>> foo.bar is foo.bar
False
票数 6
EN

Stack Overflow用户

发布于 2012-10-12 20:04:58

millimoose得到了绿色的支票,但我想我应该再加一点。

tl;dr

绑定的方法对象是暂时的。也就是说,您每次获取它们时都会重新创建它们。

代码语言:javascript
运行
复制
class Foo(object):
    def bar(object): pass

foo = Foo()
m1 = foo.bar
m2 = foo.bar
print (id(m1))
print (id(m2))

# 38121264
# 38952752

更多详细信息:描述符协议

每次获取绑定方法对象时都会重新创建它们,因为存储在类中的function对象实现了descriptor protocol

bar函数存储在类dict中:

代码语言:javascript
运行
复制
class Foo(object):
    def bar(object): pass

print (Foo.__dict__['bar'])

# <function bar at 0x00000000025F2208>

当Foo实例试图访问bar时,它没有bar。所以它在它的类中查找它,并在类dict中找到它。根据描述符协议,function对象实现了__get__方法。因此,实际调用来获取绑定方法的是:

代码语言:javascript
运行
复制
print(Foo.__dict__['bar'].__get__(foo, Foo))

# <bound method Foo.bar of <__main__.Foo object at 0x00000000025719B0>>

相当于:

代码语言:javascript
运行
复制
print (foo.bar)

# <bound method Foo.bar of <__main__.Foo object at 0x00000000025719B0>>

你可以像这样得到原始函数:

代码语言:javascript
运行
复制
print (foo.bar.im_func) # Python 2.x

# <function bar at 0x00000000025F2208>    

print (foo.bar.__func__) # Python 3.x

# <function bar at 0x00000000025F2208>   
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12848507

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档