有趣。。。我做的第一件事就是打电话给help$ python help
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
...
我看到的第一个选项是在导入时禁用自动pyc和pyo文件生成,尽管这可能导致了它的字母顺序。在
让我们做些测试
^{pr2}$
所以它只在导入时生成pyc文件。在
现在为了检查正在使用哪些文件,我将使用类似于linux truss的OS X dtruss来执行完整的跟踪。。。在$ echo '#!/bin/sh
python test.py' > test.sh
$ chmod a+x test.sh
$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"
975/0x5713: 244829 6 3 read(0x3, "#!/bin/sh \npython test.py\n\b\0", 0x50) = 26 0
975/0x5713: 244874 4 2 read(0xFF, "#!/bin/sh \npython test.py\n\b\0", 0x1A) = 26 0
977/0x5729: 658694 6 2 readlink("test.py\0", 0x7FFF5636E360, 0x400) = -1 Err#22
977/0x5729: 658726 10 6 getattrlist("/Users/samyvilar/test.py\0", 0x7FFF7C0EE510, 0x7FFF5636C6E0 = 0 0
977/0x5729: 658732 3 1 stat64("test.py\0", 0x7FFF5636DCB8, 0x0) = 0 0
977/0x5729: 658737 5 3 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0
977/0x5729: 658760 4 2 stat64("test.py\0", 0x7FFF5636E930, 0x1) = 0 0
977/0x5729: 658764 5 2 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0
从外观上看,python甚至都不碰它测试.pyc完全归档!在$ echo '#!/bin/sh
python -c "import test"' > test.sh
$ chmod a+x test.sh
$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"
$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"
1028/0x5d74: 654642 8 5 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0
1028/0x5d74: 654683 8 5 open_nocancel("test.pyc\0", 0x0, 0x1B6) = 4 0
$
很有意思,看起来像是打开了测试.py那么测试.pyc在
当我们删除pyc文件时会发生什么。在$ rm test.pyc
$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"
1058/0x5fd6: 654151 7 4 open_nocancel("/Users/samyvilar/test.py\0", 0x0, 0x1B6) = 3 0
1058/0x5fd6: 654191 6 3 open_nocancel("/Users/samyvilar/test.pyc\0", 0x0, 0x1B6) = -1 Err#2
1058/0x5fd6: 654234 7 3 unlink("/Users/samyvilar/test.pyc\0", 0x1012B456F, 0x1012B45E0) = -1 Err#2
1058/0x5fd6: 654400 171 163 open("/Users/samyvilar/test.pyc\0", 0xE01, 0x81A4) = 4 0
它首先打开测试.py然后它试图打开测试.pyc它返回一个错误,然后调用unlink并再次生成pyc文件。。。有意思,我以为可以查到。在
如果我们删除原始的py文件呢。在$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"
1107/0x670d: 655064 4 1 open_nocancel("test.py\0", 0x0, 0x1B6) = -1 Err#2
1107/0x670d: 655069 8 4 open_nocancel("test.pyc\0", 0x0, 0x1B6) = 3 0
怪不得它打不开测试.py但它仍然在继续,直到今天,我还不确定这是否真的“好”python应该发出某种警告,我已经被这个烧坏了好几次,不小心删除了我的文件,运行了我的测试,当它们通过时,我感到松了一口气,但当我似乎找不到的时候,我开始流汗源代码!在
在这个测试之后,我们假设python只在调用时直接使用pyc文件,比如python test.pyc或者在导入时间接使用pyc文件,否则它似乎不使用它们。在
假设CPythons编译器的设计速度相当快,它不做太多的类型检查,它可能会生成非常高级别的字节码,所以大部分的工作负载实际上是由虚拟机完成的。。。它可能一次性完成一个单一的过程,lexing->;compiler->字节码,它每次都这样做,它从命令行读取python文件,或者导入时没有pyc文件,在这种情况下,它会创建它。在
这可能就是为什么其他一些实现更快,因为它们需要更多的编译时间,但生成的字节码更原始,可以很好地优化。在
建立一个虚拟机来高效地进行纯解释是非常困难的。。。在
这一切都是关于平衡的,你的字节码越强大,你的编译器就越简单,但你的虚拟机就越复杂和缓慢,反之亦然。。。在