我想知道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列)。 我想也许如果我在读完数据之后关闭了我打开的文件,这会有所帮助,但事实并非如此。这导致我考虑执行代码行的顺序,因此我的问题。
由于
答案 0 :(得分:11)
我能想到的唯一让一些人感到惊讶的是:
def test():
try:
return True
finally:
return False
print test()
输出:
False
finally
子句实际上是最后执行的,即使它们之前有return
语句。但是,这不是Python特有的。
答案 1 :(得分:3)
C的执行当然是顺序的。甚至有定义sequence points的规则,因此您可以了解各个表达式的评估方式。
答案 2 :(得分:3)
CPython本身的编写方式使得你提到的任何效果都被最小化;代码总是在编译期间从上到下禁止文字评估,对象在其引用计数达到0时立即进行GC,等等。
答案 3 :(得分:3)
cpython vm中的执行非常线性。我不认为你遇到的任何问题都与执行顺序有关。
在Python中你应该注意的一件事但不是C:可以在任何地方提出异常,因为只是因为你看到close()
调用低于相应的open()
调用并不意味着调用实际上是到达。在任何地方使用try
/ finally
(或在足够新的pythons中使用with
语句)以确保关闭打开的文件(并且可以释放可以显式释放的其他类型的资源)。 / p>
如果您的问题与内存使用有关,而不是其他类型的资源,调试它可能会更难。无法在python中显式释放内存。 cpython vm(你最有可能使用它)会在最后一次引用它后立即释放内存,但有时无法释放存在于具有__del__
方法的对象循环中的内存。如果您拥有自己的任何__del__
方法或使用拥有它们的类,这可能是您问题的一部分。
但是,如果没有看到更多代码,您的实际问题(内存一个,而不是执行顺序)很难回答。它可能是显而易见的(或者至少可能有一些明显的方法来减少你需要的内存量)。
答案 4 :(得分:1)
“如果我打开一个数据文件,读入数据,关闭文件,然后做其他事情我确定文件在关闭文件之后的行之前关闭了吗?”
关闭是。
从记忆中释放。不能保证何时会发生垃圾收集。
此外,关闭文件不会说明您创建的所有其他变量以及您已经放置的其他对象附加到这些变量。
没有“操作顺序”问题。
我敢打赌,你有太多的全局变量和太多的数据副本。
答案 5 :(得分:0)
如果数据由列和行组成,为什么不使用内置文件迭代器一次获取一行?
f = open('file.txt')
first_line = f.next()
答案 6 :(得分:0)
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)
如果出现以下情况, fork()函数可能会失败:
[ENOMEM]
存储空间不足。
os.popen4
最终调用open2.Popen4.__init__
,fork
必须fork
才能创建您尝试读取/写入的子进程。此基础调用失败,可能是由于资源耗尽。
您可能在其他地方使用了太多内存,导致{{1}}尝试使用超过为您的用户提供的RLIMIT_DATA或RLIMIT_RSS限制。根据{{3}}的建议,Python memory profiler - Stack Overflow可以帮助您确定是否属于这种情况。