我为我的最后一年项目的一小部分python代码构建了一个优化编译器。我正在做的第一件事是测试变量是否涉及或导致I / O.如果我要静静地跟踪一个函数调用谚语中的兔子洞,我究竟怎么知道它涉及I / O?是否会调用内置的python函数,如print,input或内置的'file'对象函数调用来进行读写?
我没有太多时间来做这个项目(只有6个月),所以我完全无视人们在C中编写I / O,包装它的某种python对象并从python中调用它。
是否生成了表示是否存在I / O的字节代码?或者它与AST一样无益?
如果它是可撤销的,那就没什么大不了的,我只需要我的项目的I / O子集进行打印,输入读写。那或做活体分析。
感谢。
答案 0 :(得分:2)
这并不像查看字节码那么简单,因为对事物的调用只是符号查找:
>>> def write_to_a_file(s):
f = open('foo.txt', 'w')
f.write(s)
f.close()
>>> import dis
>>> dis.dis(write_to_a_file)
2 0 LOAD_GLOBAL 0 (open)
3 LOAD_CONST 1 ('foo.txt')
6 LOAD_CONST 2 ('w')
9 CALL_FUNCTION 2
12 STORE_FAST 1 (f)
3 15 LOAD_FAST 1 (f)
18 LOAD_ATTR 1 (write)
21 LOAD_FAST 0 (s)
24 CALL_FUNCTION 1
27 POP_TOP
4 28 LOAD_FAST 1 (f)
31 LOAD_ATTR 2 (close)
34 CALL_FUNCTION 0
37 POP_TOP
38 LOAD_CONST 0 (None)
41 RETURN_VALUE
他们自己的字节码只是加载东西,调用东西和存储东西。如果你在字节码级别操作,你实际上必须查看有效负载。
Check out the current list of Python bytecodes你可以看到那里没有任何可以区分I / O调用的东西。
即使你要检查所有LOAD_GLOBAL
个电话或LOAD_FAST
个电话并应用白名单,这也不一定有效,因为有些模块提供I / O且字节码不是真的帮助你:
>>> def uses_a_module_for_io(s):
import shutil
shutil.copy(s, 'foo.txt')
>>> dis.dis(uses_a_module_for_io)
2 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (shutil)
9 STORE_FAST 1 (shutil)
3 12 LOAD_FAST 1 (shutil)
15 LOAD_ATTR 1 (copy)
18 LOAD_FAST 0 (s)
21 LOAD_CONST 2 ('foo.txt')
24 CALL_FUNCTION 2
27 POP_TOP
28 LOAD_CONST 0 (None)
31 RETURN_VALUE
>>> def doesnt_use_shutil_really(s):
shutil = object()
shutil.copy = lambda x,y: None
shutil.copy(s, 'foo.txt')
>>> dis.dis(doesnt_use_shutil_really)
2 0 LOAD_GLOBAL 0 (object)
3 CALL_FUNCTION 0
6 STORE_FAST 1 (shutil)
3 9 LOAD_CONST 1 (<code object <lambda> at 011D8AD0, file "<pyshell#29>", line 3>)
12 MAKE_FUNCTION 0
15 LOAD_FAST 1 (shutil)
18 STORE_ATTR 1 (copy)
4 21 LOAD_FAST 1 (shutil)
24 LOAD_ATTR 1 (copy)
27 LOAD_FAST 0 (s)
30 LOAD_CONST 2 ('foo.txt')
33 CALL_FUNCTION 2
36 POP_TOP
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
请注意,LOAD_FAST
的{{1}}可以是用户刚刚组成的内容。在我的情况下,我只是将它作为通用对象,但用户也可以在其路径上使用不同的shutil
。