[奇用]嵌入式函式
沈崴 <[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]