如何在侧输出中显示python输入代码

时间:2018-06-05 20:23:07

标签: python logging

我想知道是否有将python脚本的输入和输出重定向到文件以便它们被隔行扫描。基本上我说我有以下代码:

x = 1
print("hello, world")
print(x)
x = 2
print(x)

def myfun(Val):
    return(Val+1)
myfun(7)

我会寻找以下内容显示在输出文件

x = 1
print("hello, world")
"hello, world"
print(x)
1
x = 2
print(x)    
2

def myfun(Val):
    return(Val+1)
myfun(7)
8

我已经看过的事情包括:

  • 简单文件重定向python myfile.py > output.log但是这不会捕获输入

  • 跟踪模块python -m trace myfile.py然而,它显示方式太多信息并使运行时膨胀。我找不到任何明显的方法将此限制为顶级代码(不是每个模块和函数调用)

  • Jupyter笔记本 - 我很欣赏它们清楚地显示输入和输出但是我真的想把它保存到命令行可执行脚本和基本的ascii python文件。

理想情况下,我希望找到某种带有重定向的bash魔法,python命令行选项或能够处理此问题的常见python模块,但到目前为止还没有运气:(

编辑: 作为进一步的澄清示例,我试图从R重新创建以下功能。假设我们将R程序myprog.R作为:

myfun <- function(x){
    x + 1
}
y <- myfun(7)

print("hello,world!")
print(y)
y + 1

然后从命令行R CMD BATCH myprog.R运行会生成文件myprog.Rout,看起来像

myfun <- function(x){
    x + 1
}
y <- myfun(7)

print("hello,world!")
[1] "hello,world!"

print(y)
[1] 8

y + 1
[1] 9

4 个答案:

答案 0 :(得分:1)

[编辑]这是一个非常有限的脚本,不幸的是,如果您的代码变得更复杂(意味着语句跨越多行),这会立即中断,就像拥有一个函数一样简单。

对于非常简单的usecase示例,您可以使用如下的中间脚本(假设文件名为rt.py):

import sys

in_file = sys.argv[1]

with open(in_file) as script:
    for line in script:
        line = line.strip()
        if line:
            # Option to visually separate it by using repr
            # print(repr(line))
            print(line)
            # Another optional use a prefix
            # print(">>>", end="")
            exec(line)

现在您可以将现有脚本传递给它

python rt.py somescript.py

基于缩进来提升脚本是不可能的,但这可能是不值得的,我希望其他解决方案存在,我不知道。

答案 1 :(得分:0)

假设输入文件名为a.py,则会重定向eval调用的stdout,以便可以捕获它,然后将其与源文件一起写入文件(out.py)。

就像dparolin所说的那样,虽然只要你有块就可以使用简单的脚本,但事情就会崩溃。

import sys
from io import StringIO
import contextlib


filename="a.py"
f= open(filename,"r")
f_out= open("out.py","w+")

SCRIPT_LOCALS={}

@contextlib.contextmanager
def stdoutIO(stdout=None):
    old = sys.stdout
    if stdout is None:
        stdout = StringIO()
    sys.stdout = stdout
    yield stdout
    sys.stdout = old

def eval_with_return(str_code):
    with stdoutIO() as s:
        exec(str_code,SCRIPT_LOCALS)
        return s.getvalue()


for line in f:
    orig_line=line if line.endswith("\n") else line+"\n"
    sys_out_res=eval_with_return(line)
    f_out.write(orig_line)
    f_out.write(sys_out_res)

f.close()
f_out.close()

范围来自here。 上下文管理器重定向来自here

答案 2 :(得分:0)

作为替代方案,您可以解析跟踪模块创建的输出并切断您不喜欢的部分。在这个例子中,我将自己局限于前缀和模块打印输出。 请注意,如果没有正确格式化(PEP8)代码,这也会轻易地删除功能定义,但这可能是一个功能而不是错误;-) 在默认情况下,使用trace不会为您提供函数内容。取决于你究竟需要什么。

将以下内容保存为trace_rt.py并使用如下

python -m trace -t yourfile.py | trace_rt.py

trace_rt.py:

import sys


def cutoff(in_line):
    """Removes trace prefix if present"""
    if "): " in line:
        return line.split("): ")[1]
    elif line.startswith("--- modulename:"):
        return ""
    return line


for line in sys.stdin:
    line = line.strip()
    if line:
        print(cutoff(line))

答案 3 :(得分:0)

一种相当简单的方法是将代码粘贴到交互式Python shell中,即打开文件,复制内容,运行python而不使用文件参数,然后粘贴内容。

示例文件:

def foo(n):
    if n % 2 == 0:
        return n**2
    else:
        return n**.5

x = 41
print(foo(x))
print(foo(2 * x))

输出:

>>> def foo(n):
...     if n % 2 == 0:
...         return n**2
...     else:
...         return n**.5
... 
>>> x = 41
>>> print(foo(x))
6.4031242374328485
>>> print(foo(2 * x))
6724

这会将>>>...前缀添加到代码行中,但这实际上可能有助于输出的可读性。此外,代码文件必须用空格缩进(没有制表符),并且块(如函数定义)必须以额外的空行终止,否则它们将无法工作。