0

Python: как получить вывод print в выражении exec

13

Я хочу получить вывод функции exec(...). Вот мой код:

code = """
i = [0,1,2]
for j in i :
    print(j)
"""
result = exec(code)

Как я могу получить то, что выводится с помощью print? Как получить что-то вроде:

0
1
2

С уважением и спасибо.

5 ответ(ов)

0

С начала 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.

0

Вы можете перенаправить стандартный вывод в строку на время выполнения вызова 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().

0

Вот версия ответа от @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(), который содержит весь вывод.

0

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(...) может быть опасным и нежелательным:

  1. Ваш код может стать трудным для понимания и сопровождения, напоминая неуправляемый "goto".
  2. Может возникнуть возможность инъекции кода от конечного пользователя.
  3. Исключения вызывают путаницу в стеке, поскольку exec работает в контексте потоков, что тоже может привести к проблемам.

Рекомендуется избегать использования exec, если это возможно, или хотя бы использовать его с осторожностью.

0

Вот небольшая поправка к ответу Фредерика. Нам нужно обработать возможное исключение в 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. Также в блоке обработки исключений можно добавить более детализированную обработку, если это необходимо.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь