#python #python-3.x
#python #python-3.x
Вопрос:
Документы Python: os.popen
:
Откройте канал в команду или из команды. Возвращаемое значение представляет собой открытый файловый объект, подключенный к каналу, который может быть прочитан или записан в зависимости от того, установлен ли режим ‘r’ (по умолчанию) или ‘w’.
Я могу использовать next
метод X.__next__()
/ X.next()
(2.X), но не next(x)
вызов,
- разве
__next__
метод иnext(x)
метод не совпадают? - почему мы не можем использовать
next(x)
объект foros.popen
?
И последнее, но не менее важное: как next()
на самом деле работает next
метод and ?
Комментарии:
1. Вы получаете какие-либо ошибки
next()
?2. да, ошибка типа: объект _wrap_close не является итератором
3.
next(x)
на самом деле работает в Python 2, но не работает в Python 3 для меня (за исключением, которое вы показываете).5. @vicious_101: тогда почему бы
iter()
сначала не вызвать его?
Ответ №1:
Глядя на исходный код (Python 3.4), кажется __next__
, что метод не реализован в _wrap_close
классе, поэтому 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)
Комментарии:
1. Например, это итерируемый, а не итератор. Сначала вызовите
iter()
его.2. @eryksun: верно, я на самом деле не заметил
__getattr__
; но специальные методы всегда просматриваются непосредственно по типу и__getattr__
не вызываются тогда.hasattr(type(os_open_return_value), 'next')
имеет значение false, поэтому оболочка не является итератором. Если__iter__
бы вместо этого был возвращенself
и прокси-сервер также предложилnext()
метод, все это сработало бы, но я предполагаю, что есть причина, по которой они этого не сделали?_wrap_close
Используется для чего-то, что является только итерируемым, а не итератором?3. @eryksun: ну,
__iter__
не был реализован какreturn self
, а скорееreturn iter(self._stream)
. Ошибка в том, что прокси-сервер является итеративным, а не итератором.4. Хорошо, я понял часть о
os.popen()
возвратеos._wrap_close
объекта, у которого нет__next__
метода. Однако я не понимаю вашего комментария о перезаписанном__getattr__
методе, потому что я не могу найти его в вашем примере кода. Не могли бы вы объяснить эту часть более подробно?5. @Soong Когда мы вызываем
next()
экземпляр, он ищет__next__
метод в классе (не в экземпляре), поскольку в нем нет__next__
метода,_wrap_close
вы получите сообщение об ошибке. С другой стороны, когда вы вызываете.__next__()
экземпляр, Python ищет__next__
метод в экземпляре, а затем в классе, когда он не найден__getattr__
, вызывается, и оттуда они делегируют вызов базовомуio.TextIOWrapper(proc.stdin)
объекту.
Ответ №2:
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.txtn'