使用getattr获取方法的对象引用

时间:2013-02-12 00:46:12

标签: python function object reference getattr

说,我有以下class名为Testmethod名为start

>>> class Test:
...     def __init__(self, *args, **kwargs):
...         pass
...     def start(self):
...         pass
... 

现在,我有一个名为function

的独立独立func
>>> def func():
...     print 'this is a func and not a method!!!'
... 
>>> 

[1] 现在,t.startmethod的{​​{1}},属于instance of __main__.Test

0xb769678c

[2] >>> t = Test() >>> t.start <bound method Test.start of <__main__.Test instance at 0xb769678c>> >>> func,属于function

0xb767ec6c

现在,我们可以使用内置>>> func <function func at 0xb767ec6c> >>> __module__t.start中提取func。毫不奇怪,__module__func属于同一t.start,即module

__main__

[3] 现在,我们将>>> func.__module__ '__main__' >>> t.__module__ '__main__' >>> __module__存储在变量t.start

obj

现在,我使用>>> obj = __import__(t.start.__module__) >>> obj <module '__main__' (built-in)> >>> 获取函数getattr()的{​​{1}}句柄func,如下所示<function func at 0xb767ec6c>的输出为func到[2]

getattr()

问题:

如何使用identical和模块名称[3]来获取>>> print getattr(obj, 'func') <function func at 0xb767ec6c> >>> >>> print getattr(__import__('__main__'), 'func') <function func at 0xb767ec6c> >>> [1]的句柄getattr()

当我尝试在Test.start上使用<bound method Test.start of <__main__.Test instance at 0xb769678c>>时,我得到了以下getattr()

't.start'

换句话说,我有两个数据。他们是

  1. Traceback
  2. 刺痛>>> print getattr(obj, 'Test.start') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'Test.start' >>> >>> >>> print getattr(__import__('__main__'), 'Test.start') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'Test.start' >>>
  3. 现在,如何获取__import__('__main__')的句柄(请注意'Test.start'此处)t.start

3 个答案:

答案 0 :(得分:2)

我不确定我是否理解你的问题,但我认为这符合你的要求:

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print 'this is a func and not a method!!!'

t = Test()

module = __import__(t.start.__module__)

print vars(module)['Test'].start
print vars(module)['func']
print vars(module)['t'].start

输出:

<unbound method Test.start>                                        
<function func at 0x00BA67F0>                                      
<bound method Test.start of <__main__.Test instance at 0x00BAC170>>

答案 1 :(得分:1)

obj = __import__(t.start.__module__)    

test_class = getattr(obj, 'Test')

print getattr(test_class, 'start')

我不确定你是否需要直接从模块中获取(或者即使可能):/

你也可以使用:

obj = __import__(t.start.__module__)

print obj.__dict__["Test"].__dict__["start"]

但您要求getattr()所以......

答案 2 :(得分:0)

我想知道你为什么写obj = __import__(t.start.__module__)
我认为为主模块保留一个名称,以便有可能获得模块命名空间中的对象作为模块的属性,这要归功于 getattr()功能。

我告诉你,你不必做这个伎俩。 globals()是一个字典,表示主空间的全局命名空间。 然后你可以编写globals()["func"]来获取对象 func

我还告诉您,除了getattr(N,"xyz")之外,还有另一种方法可以在对象 N 的命名空间中获取对象 xyz ,这要归功于其名称{ {1}}, 它是xyz方法的: __dict__可以访问对象 N

的命名空间

我想知道你的问题是否存在于Python的微妙之中,导致你出错。

在您的问题中,在您撰写N.__dict__的地方和您撰写t.__module__的其他地方。 对于这两种情况,结果相同并等于t.start.__module__

然而,
1) t 没有名称"__main__"的属性
2) t 甚至没有名称__module__的属性! 如果您打印start,则会看到结果为t.__dict__

开始并非真正属于 t 实例的命名空间,因为它实际上属于测试 <的命名空间/ p>

以下代码证明了这些肯定:

{ }

结果

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

y = Test()
y.ku = 102

print 'y.__dict__',y.__dict__
print 'Test.__dict__',Test.__dict__

表达式y.__dict__ {'ku': 102} Test.__dict__ {'start': <function start at 0x011E11B0>, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x011E1170>} t.__module__无论如何给出答案的原因可以通过以下引文解释:

  

实例具有作为字典实现的名称空间   搜索属性引用的第一个地方   当一个   在那里找不到属性,并且实例的有一个   通过该名称的属性,搜索继续该类   属性。

     

http://docs.python.org/2/reference/datamodel.html#index-55

因此:
1) t 没有名称t.start.__module__的属性,然后Python在 t 类中搜索它 2) t 没有名称__module__的属性,然后Python在 t

类中搜索它

那么,Python进入 t 类来查找startt.__module__的值。 通过以上引用描述的这种机制可以用以下代码观察:

t.start.__module__

我的意思是Python回答名称为class Test: def __init__(self, *args, **kwargs): pass def start(self): pass t = Test() print 'getattr(t,"start")' print getattr(t,"start") # result is getattr(t,"start") <bound method Test.start of <__main__.Test instance at 0x011DF288>> t 的属性为 Test.start ,而不是 t.start

因此,从"start"t.start.__module__的事实来看,在我看来,您可能认为 t.start 属于模块命名空间,因此您应该能够写出与"__main__"类似的内容来获取对象开始

但这是假的 您无法在模块的global namespace =命名空间中找到方法 start (我编写METHOD),因为它位于 Test 的命名空间中。你必须通过实例或类或通过类本身来实现它,作为一种方法。


还有一件事。
我精确地使用了METHOD,因为我认为方法 t.start 基于 FUNCTION ,它与它不同,而位于模块中&# 39; s名称空间。实际上,方法是指向实例和指向此全局命名空间函数的指针的包装器:

  

如果你仍然不明白方法是如何工作的,那么看看   实施也许可以澄清问题。当一个实例属性   引用的不是数据属性,搜索其类。如果   name表示一个有效的class属性,它是一个函数对象,a   方法对象是通过打包(指向)实例对象来创建的   和一个在抽象对象中一起找到的函数对象:   这是方法对象。用方法调用方法对象时   参数列表,从实例构造一个新的参数列表   对象和参数列表,以及调用函数对象   这个新的参数列表。

     

http://docs.python.org/2/tutorial/classes.html#method-objects

我想要强调的是,似乎某个方法所基于的某个函数(不是方法)存在。

我认为这个功能在于模块名称空间,这就是getattr(obj,"func")的原因。 给
Test.__dict__["start"]

<function start at 0x011E40F0>
getattr(Test,"start")

getattr(t,"start")
<unbound method Test.start>
没有本地化绑定和未绑定的方法。

所以,在我看来,只要我正确地理解了doc(没有很好地解释这些要点,顺便说一下,我发现)一个方法是一个包装器,它基于一个真实的位于模块命名空间中的函数,以及<bound method Test.start of <__main__.Test instance at 0x011DF530>>t.start.__module__Test.start.__module__

的原因

模块命名空间中存在一个函数似乎有点奇怪,当我们用"__main__"打印它们时,它们不会出现在模块的属性中:

globals()

结果

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print 'this is a func and not a method!!!'

t = Test()

print '* globals()["func"]'
print globals()["func"]
print id(globals()["func"])
print "===================================="
print '* Test.__dict__["start"]'
print Test.__dict__["start"]
print id(Test.__dict__["start"])
print '----------------------------------------------'
print '* getattr(Test,"start")'
print getattr(Test,"start")
print id(getattr(Test,"start"))
print '----------------------------------------------'
print '* getattr(t,"start")'
print getattr(t,"start")
print id(getattr(t,"start"))
print "===================================="
print globals()

但事实是我们确实看到* globals()["func"] <function func at 0x011C27B0> 18622384 ==================================== * Test.__dict__["start"] <function start at 0x011DEFB0> 18739120 ---------------------------------------------- * getattr(Test,"start") <unbound method Test.start> 18725304 ---------------------------------------------- * getattr(t,"start") <bound method Test.start of <__main__.Test instance at 0x011DF418>> 18725304 {'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 't': <__main__.Test instance at 0x011DF418>, 'func': <function func at 0x011C27B0>, 'Test': <class __main__.Test at 0x011DC538>, '__name__': '__main__', '__doc__': None} 函数,其地址18739120与绑定和未绑定方法地址18725304不同。
此外,我不知道哪些其他解释可以解释所揭露事实的全部。

事实上,没有收到任何指定名称的函数不会出现在模块名称空间中,这一点并不奇怪。
它是一个内部函数,是Python必需的,而不是程序员可以使用的。


关于 func ,使用您使用的所有方法:

Test.__dict__["start"]

结果

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print 'this is a func and not a method!!!'

t = Test()
print 'func --->',func
print id(func)

print '\nobj = __import__(t.start.__module__)  done\n'
obj = __import__(t.start.__module__)

print '* globals()["func"]'
print globals()["func"]
print id(globals()["func"])
print '* obj.__dict__["func"]'
print obj.__dict__["func"] 
print "* getattr(obj, 'func')"
print getattr(obj, 'func')
print "* getattr(__import__('__main__'), 'func')"
print getattr(__import__('__main__'), 'func')

现在使用func ---> <function func at 0x011C2470> 18621552 obj = __import__(t.start.__module__) done * globals()["func"] <function func at 0x011C2470> # <== address in hexadecimal 18621552 # <== address in decimal * obj.__dict__["func"] <function func at 0x011C2470> * getattr(obj, 'func') <function func at 0x011C2470> * getattr(__import__('__main__'), 'func') <function func at 0x011C2470>

拆分您的方法
obj

结果

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

print 'Test.start -->',Test.start
print id(Test.start)
print '----------------------------------------------'
print '* Test.__dict__["start"]'
print Test.__dict__["start"]
print id(Test.__dict__["start"])

print '* getattr(Test,"start")'
print getattr(Test,"start")
print id(getattr(Test,"start"))
print '\n'


print 't.start -->',t.start
print id(t.start)
print '----------------------------------------------'
print '* t.__dict__["start"]'
try:
    print t.__dict__["start"]
    print id(t.__dict__["start"])
except KeyError as e:
    print 'KeyError :',e

print '* getattr(t,"start")'
print getattr(t,"start")
print id(getattr(t,"start"))

到现在为止,我很少使用Test.start --> <unbound method Test.start> 18725264 ---------------------------------------------- * Test.__dict__["start"] <function start at 0x011E40F0> 18759920 * getattr(Test,"start") <unbound method Test.start> 18725264 t.start --> <bound method Test.start of <__main__.Test instance at 0x011DB940>> 18725264 ---------------------------------------------- * t.__dict__["start"] KeyError : 'start' * getattr(t,"start") <bound method Test.start of <__main__.Test instance at 0x011DB940>> 18725264

我在这些结果中意识到getattr( )以特定方式给出了结果:属性 start 被描述为一种方法,如果通过实例或通过实例获得,则绑定或不绑定一堂课。

但是,只有getattr( )才能提供有关对象真实属性的准确信息 因此,我们看到 start 并非真正位于实例的命名空间中,而是仅存在于类的命名空间中。
它被描述为当它作为命名空间__dict__的元素时的函数,并且当通过Test.__dict__作为属性给出时是一种方法。在最后一种情况下没有给出地址。

使用 vars()函数可以得到相同的结果。