[奇用]嵌入式函式
沈崴 <[email protected]> reply-to [email protected] to python-cn`CPyUG`华蟒用户组 <[email protected]> date Wed, Oct 15, 2008 at 16:37 subject [CPyUG:68306] 新手提问, 为什么有中间变量和没有中
现象
理解
- ZoomQuiet
- 这又是魔术之一,在函式中制造函式,没有运行函式前,名称空间中是没有那个 print_a() 的;这不是中间变量,根本就是 运行时 mix-in
字节码
onenew <[email protected]> reply-to [email protected] to [email protected] date Wed, Oct 15, 2008 at 17:37 subject [CPyUG:68319] Re: 新手提问, 为什么有中间变量和没有中间变量的结果是不一样的
>>> from dis import dis >>> print dis(test()[1].print_a) test() 3 0 LOAD_NAME 0 (type) 3 LOAD_NAME 1 (sys) 6 CALL_FUNCTION 1 9 LOAD_CONST 1 ('<string>') 12 CALL_FUNCTION 1 15 STORE_FAST 0 (m) 6 18 LOAD_CONST 2 ("\na = 'hello world!';\ndef print_a():print a ") 21 LOAD_FAST 0 (m) 24 LOAD_ATTR 2 (__dict__) 27 DUP_TOP 28 EXEC_STMT 7 29 LOAD_FAST 0 (m) 32 RETURN_VALUE temp.print_a() & test().print_a() 3 0 LOAD_GLOBAL 0 (a) 3 PRINT_ITEM 4 PRINT_NEWLINE 5 LOAD_CONST 0 (None) 8 RETURN_VALUE
以上是两个函数对应的字节码 问题关键就在 LOAD_GLOBAL 的解释
- 猜想
- 两种执行方式的GLOBAL 是不同的
- temp = test() 这样temp成为一个模块对象 有了自己的名字空间 temp.print_a的GLOBAL 是这个空间
- test().print_a() 本身是一个表达式python可能内部做了优化,在查找GLOBAL 的时候直接使用了表达式所在的名字空间
抛砖引玉了:)
-- 知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得。
继续
又测试了一下 看来不是对 global查找策略的优化(ps:如果是直接查找顶层名字空间会出异常的), 而是对初始化时机的优化.细节只有去抠源码了.
>>> import sys >>> def test(): ... #print "calling test()" ... m = type(sys)('<string>') ... d = m.__dict__ ... exec '''\ >>> a = 'hello world!'; >>> def print_a():print a''' in d ... #print d['a']# -> hello world! ... #print m.a# -> hello world! ... #print "test() end" ... return d,m ---------------------------------------- >>> pprint (test()[0]) {'__builtins__': {}, '__doc__': None, '__name__': None, 'a': None, 'print_a': None} #模块的字典尚未初始化 ---------------------------------------- >>> pprint (test()[1].__dict__ == test()[0] ) #模块的字典尚未初始化 True >>> print test()[1].__dict__['a'] # -> hello world!#模块的字典完成初始化 None >>> print test()[1].a # -> hello world!#模块的字典完成初始化 hello world! ---------------------------------------- >>> d,m=test() >>> pprint (d) {'__builtins__': {}, '__doc__': None, '__name__': '<string>', # 'a': 'hello world!', 'print_a': <function print_a at 0x01D2FF70>}#模块的字典完成初始化 >>> pprint (m.__dict__['a'])#模块的字典完成初始化 'hello world!' >>> print m.a # -> hello world!#模块的字典完成初始化 hello world! ----------------------------------------
}看起来, 模块创建的时候字典里只有键,值都是none (注意看 __name__) 被使用,或者被命名的时候才初始化字典的值. 以前倒是没注意过,python的手册有提过这种优化?
BUG
沈崴 <[email protected]> reply-to [email protected] to python-cn`CPyUG`华蟒用户组 <[email protected]> date Thu, Oct 16, 2008 at 08:50 subject [CPyUG:68360] Re: 新手提问, 为什么有中间变量和没有中间变量的结果是不一样的
On Oct 15, 8:16 pm, 杨晨醒 <[email protected]> wrote:
> 感觉还是没有解释heroboy的那段代码里的现象啊...... > 按照那段代码,f['a']已经被初始化了,但是返回出去之后却取不出['a']
cpython 的这种情况应该可以归入 bug 的范畴了。
另外使用 PyPy 来执行这个代码, 能得到正确的结果。
反馈
创建 by -- ZoomQuiet [2008-10-15 09:18:32]