Python: как получить вывод print в выражении exec
Я хочу получить вывод функции exec(...)
. Вот мой код:
code = """
i = [0,1,2]
for j in i :
print(j)
"""
result = exec(code)
Как я могу получить то, что выводится с помощью print
?
Как получить что-то вроде:
0
1
2
С уважением и спасибо.
5 ответ(ов)
С начала Python 3.4 существует встроенное решение для перенаправления stdout
в стандартной библиотеке: contextlib.redirect_stdout.
Пример использования:
from io import StringIO
from contextlib import redirect_stdout
f = StringIO()
with redirect_stdout(f):
help(pow)
s = f.getvalue()
Если вы используете более старую версию Python, вы можете создать свой собственный контекстный менеджер для замены stdout
:
import sys
from io import StringIO
import contextlib
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
code = """
i = [0,1,2]
for j in i:
print(j)
"""
with stdoutIO() as s:
exec(code)
print("out:", s.getvalue())
В этом примере мы создаем контекстный менеджер stdoutIO
, который временно перенаправляет стандартный вывод в объект StringIO
. После выполнения кода любой вывод, который должен был бы пойти в консоль, будет доступен через объект StringIO
.
Вы можете перенаправить стандартный вывод в строку на время выполнения вызова exec
:
Python2
import sys
from cStringIO import StringIO
code = """
i = [0,1,2]
for j in i:
print(j)
"""
old_stdout = sys.stdout
redirected_output = sys.stdout = StringIO()
exec(code)
sys.stdout = old_stdout
print(redirected_output.getvalue())
Python3
import sys
from io import StringIO
code = """
i = [0,1,2]
for j in i:
print(j)
"""
old_stdout = sys.stdout
redirected_output = sys.stdout = StringIO()
exec(code)
sys.stdout = old_stdout
print(redirected_output.getvalue())
В приведенных примерах создается временный объект StringIO
, который перенаправляет стандартный вывод. После выполнения кода, стандартный вывод восстанавливается, и вы можете получить его содержимое с помощью метода getvalue()
. Это позволяет захватить любой вывод print()
, выполняемый внутри кода, переданного в exec()
.
Вот версия ответа от @Jochen, адаптированная для Python 3. Я также добавил блок try-except
, чтобы обработать возможные ошибки в коде.
import sys
from io import StringIO
import contextlib
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
code = """
i = [0,1,2]
for j in i:
print(j)
"""
with stdoutIO() as s:
try:
exec(code)
except Exception as e:
print("Что-то не так с кодом:", str(e))
print("Результат:", s.getvalue())
В этом коде я использую менеджер контекста stdoutIO
для временного перенаправления стандартного вывода в объект StringIO
. Это позволяет захватывать вывод, который генерирует исполняемый код. Если возникают ошибки во время выполнения exec(code)
, они обрабатываются и выводится сообщение об ошибке. После выполнения кода результат можно получить из s.getvalue()
, который содержит весь вывод.
Python 3: Как получить вывод exec в переменную
Чтобы сохранить вывод, генерируемый функцией exec()
, в переменной, вы можете использовать модуль io
для перенаправления стандартного вывода. Вот пример кода, который демонстрирует этот процесс:
import io
import sys
# Отображение версии Python (для справки)
print(sys.version)
# Сохраняем текущий stdout
old_stdout = sys.stdout
# Создаем новый экземпляр StringIO для захвата вывода
new_stdout = io.StringIO()
# Перенаправляем stdout на новый StringIO
sys.stdout = new_stdout
# Код, выполнение которого мы хотим захватить
mycode = """print( local_variable + 5 )"""
local_variable = 2
exec(mycode)
# Читаем вывод из StringIO и сохраняем его в переменную
result = sys.stdout.getvalue().strip()
# Восстанавливаем stdout
sys.stdout = old_stdout
print("Результат выполнения mycode: '" + str(result) + "'")
Этот код выведет:
3.4.8
Результат выполнения mycode: '7'
Важно!
Имейте в виду, что использование exec(...)
может быть опасным и нежелательным:
- Ваш код может стать трудным для понимания и сопровождения, напоминая неуправляемый "goto".
- Может возникнуть возможность инъекции кода от конечного пользователя.
- Исключения вызывают путаницу в стеке, поскольку
exec
работает в контексте потоков, что тоже может привести к проблемам.
Рекомендуется избегать использования exec
, если это возможно, или хотя бы использовать его с осторожностью.
Вот небольшая поправка к ответу Фредерика. Нам нужно обработать возможное исключение в exec()
, чтобы вернуть нормальный stdout
. В противном случае мы не увидим последующие выводы print
:
code = """
i = [0, 1, 2]
for j in i:
print(j)
"""
from io import StringIO
import sys
old_stdout = sys.stdout
redirected_output = sys.stdout = StringIO()
try:
exec(code)
except Exception as e:
raise # или обработайте исключение по своему усмотрению
finally: # Восстанавливаем stdout
sys.stdout = old_stdout # Восстанавливаем старый stdout
print(redirected_output.getvalue())
print('Hello, World!') # Теперь мы увидим этот вывод, даже если было исключение выше
Обратите внимание, что в коде я также исправил некоторые мелкие ошибки формата. Важно использовать print()
как функцию, что Исправляет код на Python 3. Также в блоке обработки исключений можно добавить более детализированную обработку, если это необходимо.
Как вывести сообщение в stderr в Python?
В чем разница между eval, exec и compile?
Динамическое создание методов (генерация кода) в Python на этапе выполнения
Как изменить порядок столбцов в DataFrame?
'pip' не распознан как командa внутреннего или внешнего формата