4

我想知道 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 列)。我想也许如果我在读入数据后立即关闭我打开的文件,这会有所帮助,但它没有。这让我想到了代码行的执行顺序,因此我提出了问题。

谢谢

4

7 回答 7

12

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

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

print test()

输出:

False

finally子句实际上是最后执行的,即使return它们之前有一条语句。但是,这并不特定于 Python。

于 2010-01-29T15:49:24.000 回答
3

cpython vm 中的执行是非常线性的。我不认为你有什么问题与执行顺序有关。

在 Python 中你应该注意的一件事,而不是 C:异常可以在任何地方引发,所以仅仅因为你close()在相应的调用下面看到一个调用open()并不意味着调用实际上已经到达。在任何地方使用try/ finally(或with足够新的 python 中的语句)以确保打开的文件已关闭(以及其他可以显式释放的资源被释放)。

如果您的问题与内存使用有关,而不是其他类型的资源,则调试可能会更难。在 python 中不能显式释放内存。cpython vm(您最有可能使用它)确实会在对它的最后一个引用消失后立即释放内存,但有时无法释放被困在具有__del__方法的对象的循环中的内存。如果您有__del__自己的任何方法或使用具有它们的类,这可能是您的问题的一部分。

但是,如果不查看更多代码,您的实际问题(内存问题,而不是执行顺序问题)很难回答。这可能是显而易见的(或者至少有一些明显的方法可以减少您需要的内存量)。

于 2010-01-29T19:16:55.267 回答
3

对于实际语句,C 的执行当然是顺序的。甚至还有定义序列点的规则,因此您可以了解各个表达式的计算方式。

于 2010-01-29T15:39:54.287 回答
3

CPython 本身的编写方式使您提到的任何影响都被最小化;代码始终从上到下执行,除非在编译期间进行文字评估,对象在引用计数达到 0 时立即被 GC,等等。

于 2010-01-29T15:41:35.653 回答
1

“如果我打开一个数据文件,读入数据,关闭文件,然后做其他事情我是否确定在我关闭文件后的行执行之前文件已关闭??”

关闭是的。

从记忆中释放。不,不能保证何时会发生垃圾收集。

此外,关闭文件并没有说明您创建的所有其他变量以及您放置在这些变量周围的其他对象。

没有“操作顺序”问题。

我敢打赌,你有太多的全局变量和太多的数据副本。

于 2010-01-29T17:55:49.430 回答
0

如果数据由列和行组成,为什么不使用内置的文件迭代器一次获取一行?

f = open('file.txt')
first_line = f.next()
于 2010-01-29T17:58:50.220 回答
0

popen2.py

class Popen4(Popen3):
    childerr = None

    def __init__(self, cmd, bufsize=-1):
        _cleanup()
        self.cmd = cmd
        p2cread, p2cwrite = os.pipe()
        c2pread, c2pwrite = os.pipe()
        self.pid = os.fork()
        if self.pid == 0:
            # Child
            os.dup2(p2cread, 0)
            os.dup2(c2pwrite, 1)
            os.dup2(c2pwrite, 2)
            self._run_child(cmd)
        os.close(p2cread)
        self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
        os.close(c2pwrite)
        self.fromchild = os.fdopen(c2pread, 'r', bufsize)

男人 2 叉子

如果出现以下情况, fork()函数可能会失败:

[ENOMEM]
        可用存储空间不足。

os.popen4最终调用open2.Popen4.__init__,它必须fork为了创建您尝试读取/写入的子进程。此基础调用失败,可能是由于资源耗尽。

您可能在其他地方使用了过多的内存,导致fork尝试使用超过为您的用户提供的RLIMIT_DATA或 RLIMIT_RSS 限制。正如Python 内存分析器 - Stack Overflow所推荐的那样,Heapy可以帮助您确定是否是这种情况。

于 2010-01-29T19:55:57.827 回答