2011-01-20 29 views
3

asking a question about reflection我问:python函数/方法调用有什么静态的吗?

好的答案。但是说myobject.foo()x = getattr(myobject, "foo"); x();有区别。即使它只是化妆品。在第一个foo()静态编译。在第二种情况下,字符串可以通过多种方式生成。 - 乔1小时前

这得到了答案:

嗯,马铃薯/马铃薯...在python,niether是静态编译,所以它们都或多或少等价。 - SWeko 1小时前

我知道Python对象的成员都存储在一个字典,这一切都是动态的,但我认为,鉴于以下代码:

class Thing(): 
    def m(self): 
    pass 

t = Thing() 

下面的代码会以某种方式生成.pyc文件时获得静态编译:

t.m() 

即编译器知道的m()地址,所以没有点运行时绑定。这或运行时会缓存后续查找。

而这将总是涉及击中词典:

meth = getattr(t, "m") 
meth() 

是否所有调用视为字典字符串查找?或者这两个例子实际上是相同的吗?

回答

7

他们并不完全一样,但它们都是字典查找,如可以用反汇编dis.dis显示。

特别是,请注意LOAD_ATTR指令通过名称动态查找属性。根据文档,它“用getattr(TOS, co_names[namei])”替代了TOS [栈顶​​]。

>>> from dis import dis 
>>> dis(lambda: t.m()) 
    1   0 LOAD_GLOBAL    0 (t) 
       3 LOAD_ATTR    1 (m) 
       6 CALL_FUNCTION   0 
       9 RETURN_VALUE   
>>> dis(lambda: getattr(t, 'm')()) 
    1   0 LOAD_GLOBAL    0 (getattr) 
       3 LOAD_GLOBAL    1 (t) 
       6 LOAD_CONST    0 ('m') 
       9 CALL_FUNCTION   2 
      12 CALL_FUNCTION   0 
      15 RETURN_VALUE   
+0

+1为非常有趣的答案! – rubik 2011-01-20 12:54:38

3

所有调用都被视为字典查找(好吧,内部python可能会做某种优化,但就其工作原理而言,您可以假设它们是字典查找)。

Python中没有静态编译。这是可能的,即使这样做:

t = Thing() 
t.m = lambda : 1 
t.m() 
1

不仅类可以在运行时修改(如HS example);但即使是class的关键字是“执行”在运行时:

类定义是一个可执行 声明。它首先评估 继承列表(如果存在)。继承列表中的每个 项目应该 评估为允许子类化的类对象或类型 类型。 类的套件然后在 新执行框架中执行(请参见 命名和绑定一节),使用新创建的本地名称空间 和原始全局命名空间 。 (通常,该套件仅包含功能 定义。)当类的套件 完成执行时,其执行 帧将被丢弃,但其本地 名称空间被保存。 [4]然后使用基类的继承 列表和 属性字典的 保存的本地名称空间创建类对象 。类名 绑定到 原始本地名称空间中的此类对象。

Python language reference 7.7: Class Definitions

换句话说,在启动时,解释器执行class块中的代码,并保持所得到的上下文。在编译时,无法知道类将如何。

2

这取决于您是在询问Python的语言还是特定的实现(如CPython)。

语言本身并没有说这两者是相同的,所以可能会以某种方式优化直接属性访问。然而,Python的动态特性使得难以一致地实现这一点,所以在CPython中,两者实际上是完全相同的。

说了这么多,直接t.m()可以是大约快两倍,使用getattr(),因为它涉及到一个字典查询,而不是你getattr()得到两个:即全局名称getattr()本身在字典中查找。

1

使用getattr您可以访问名称不是有效标识符的属性,但我不确定是否有使用像这样的属性的用例,而不是使用字典。

>>> setattr(t, '3', lambda : 4) 
>>> t.3() 
    File "<stdin>", line 1 
    t.3() 
    ^
SyntaxError: invalid syntax 
>>> getattr(t, '3')() 
4 
相关问题