Python 执行顺序

4 投票
7 回答
10219 浏览
提问于 2025-04-15 18:38

我在想,Python在代码执行顺序方面是否和C语言有类似的问题。

比如,我知道在C语言中,有时候某个变量在另一个变量之前没有被初始化是没有保证的。或者说,虽然一行代码在另一行的上面,但并不意味着它一定会在下面的所有代码之前执行。

那么Python也是这样吗?比如我打开一个数据文件,读取数据,关闭文件,然后再做其他事情,我能确定在我关闭文件之后,后面的代码一定会在文件关闭后执行吗?

我之所以问这个问题,是因为我正在尝试读取一个很大的数据文件(1.6GB),并使用一个特定于我工作的数据处理的Python模块。当我运行这个模块时,我收到了这个错误信息:

    File "/glast01/software/ScienceTools/ScienceTools-v9r15p2-SL4/sane/v3r18p1/python/GtApp.py", line 57, in run
    input, output = self.runWithOutput(print_command)
  File "/glast01/software/ScienceTools/ScienceTools-v9r15p2-SL4/sane/v3r18p1/python/GtApp.py", line 77, in runWithOutput
    return os.popen4(self.command(print_command))
  File "/Home/eud/jmcohen/.local/lib/python2.5/os.py", line 690, in popen4
    stdout, stdin = popen2.popen4(cmd, bufsize)
  File "/Home/eud/jmcohen/.local/lib/python2.5/popen2.py", line 199, in popen4
    inst = Popen4(cmd, bufsize)
  File "/Home/eud/jmcohen/.local/lib/python2.5/popen2.py", line 125, in __init__
    self.pid = os.fork()
OSError: [Errno 12] Cannot allocate memory
>>> 
Exception exceptions.AttributeError: AttributeError("Popen4 instance has no attribute 'pid'",) in <bound method Popen4.__del__ of <popen2.Popen4 instance at 0x9ee6fac>> ignored

我猜这可能和我读取的数据大小有关(它有17608310行和22列)。我想,也许在读取数据后立即关闭我打开的文件会有所帮助,但结果并没有。这让我开始考虑代码执行的顺序,因此我才问这个问题。

谢谢

7 个回答

3

CPython的写法是为了尽量减少你提到的那些影响;代码的执行顺序总是从上到下,除了在编译时会进行一些字面量的评估,另外,当对象的引用计数降到0时,它们会立刻被垃圾回收。

3

在CPython虚拟机中,代码的执行是非常线性的。我觉得你遇到的问题跟执行顺序没有关系。

在Python中有一点需要注意,而在C语言中则不需要:异常可以在任何地方被抛出。所以,即使你看到一个close()的调用在对应的open()调用下面,也不意味着这个close()一定会被执行。为了确保打开的文件能够被关闭(还有其他可以被明确释放的资源也能被释放),最好在代码中到处使用try/finally(或者在较新版本的Python中使用with语句)。

如果你遇到的问题是内存使用方面的,而不是其他资源的问题,那么调试起来可能会更困难。在Python中,内存不能被明确释放。你很可能使用的是CPython虚拟机,它会在最后一个引用消失后立即释放内存,但有时候它无法释放被循环引用的对象中的内存,尤其是那些有__del__方法的对象。如果你自己定义了__del__方法,或者使用了包含这个方法的类,这可能就是你问题的一部分。

不过,你实际的问题(关于内存的,而不是执行顺序的)没有看到更多代码是很难回答的。可能有一些明显的原因(或者至少有一些明显的方法可以减少你需要的内存量)。

12

我能想到的唯一可能让一些人感到惊讶的事情是:

def test():
    try:
        return True
    finally:
        return False

print test()

输出结果:

False

finally 语句确实是在最后执行的,即使在它之前有一个 return 语句。不过,这并不是Python特有的。

撰写回答