为什么os.popen返回的对象不支持next()调用
Python文档:os.popen
:
这个功能可以打开一个管道,用于与命令进行数据交换。返回的结果是一个打开的文件对象,这个对象可以用来读取或写入数据,具体取决于你选择的模式是'r'(默认)还是'w'。
我可以使用next
方法 X.__next__()
/ X.next()
(在2.X版本中),但不能使用next(x)
这个调用,
- 难道
__next__
方法和next(x)
不是一样的吗? - 为什么我们不能对
os.popen
的对象使用next(x)
?
最后,next()
和next
这个方法到底是怎么工作的呢?
2 个回答
0
https://docs.python.org/2/library/functions.html#next 上关于 next
的说明是:
通过调用迭代器的 next() 方法来获取下一个项目。如果提供了默认值,当迭代器没有更多项目时就返回这个默认值,否则会抛出一个 StopIteration 的错误。
这个错误信息:
TypeError: _wrap_close object is not an iterator
表示它不是一个迭代器。很可能是缺少了 __iter__
方法。
你遇到错误真是奇怪,因为在我用 Python 2.x 时,这段代码是可以正常工作的:
>>> next(os.popen('ls'))
'foo.txt\n'
6
看源代码(Python 3.4)的时候,发现_wrap_close
这个类里没有实现__next__
方法,所以当你调用next()
的时候就会失败,因为找不到这个类里的__next__
方法。而直接调用__next__
是可以成功的,因为有一个重写的__getattr__
方法。
相关的 源代码:
def popen(cmd, mode="r", buffering=-1):
if not isinstance(cmd, str):
raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
if mode not in ("r", "w"):
raise ValueError("invalid mode %r" % mode)
if buffering == 0 or buffering is None:
raise ValueError("popen() does not support unbuffered streams")
import subprocess, io
if mode == "r":
proc = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
bufsize=buffering)
return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
else:
proc = subprocess.Popen(cmd,
shell=True,
stdin=subprocess.PIPE,
bufsize=buffering)
return _wrap_close(io.TextIOWrapper(proc.stdin), proc)
# Helper for popen() -- a proxy for a file whose close waits for the process
class _wrap_close:
def __init__(self, stream, proc):
self._stream = stream
self._proc = proc
def close(self):
self._stream.close()
returncode = self._proc.wait()
if returncode == 0:
return None
if name == 'nt':
return returncode
else:
return returncode << 8 # Shift left to match old behavior
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def __getattr__(self, name):
return getattr(self._stream, name)
def __iter__(self):
return iter(self._stream)