重新定义在函数内不起作用的打印函数

Redefining print function not working within a function

我正在 python 3.x 中编写 python 脚本,我需要在其中重新定义 print 函数。当我在我的翻译中这样做时,它工作正常。但是当我使用相同的代码创建一个函数时,它给出了错误。

这是我的代码:

list = ["print('Wow!')\n", "print('Great!')\n", "print('Epic!')\n"]
old_print = print

def print(s): 
   global catstr
   catstr += s

catstr = ""
for item in list: 
    s = item
    exec(s)
print = old_print

catstr
>> 'Wow!Great!Epic!'

如您所见,我得到了我想要的结果:'Wow!Great!Epic!'

现在我使用相同的代码创建一个函数:

def execute(list):
    old_print = print
    def print(s):
        global catstr
        catstr += s
    catstr = ""
    for item in list: 
        s = item
        exec(s)
    print = old_print
    return catstr

现在当我运行这个函数使用下面的代码时:

list = ["print('Wow!')\n", "print('Great!')\n", "print('Epic!')\n"]

execute(list)

我收到以下错误:

old_print = print 
UnboundLocalError: local variable 'print' referenced before assignment

有谁知道为什么这在函数中不起作用?
任何有关如何修复它的建议将不胜感激。

解释器不会将 print 识别为内置函数,除非您明确告诉它。不要将其声明为全局的,只需将其删除(感谢 Padraic Cunningham):本地 print 将采用您想要的定义,而全局永远不会受到影响。

您还遇到了 catstr 的前向引用问题。下面的代码引出了所需的输出。

catstr = ""
def execute(list):

    def print(s):
        global catstr
        catstr += s

    for item in list: 
        s = item
        exec(s)
    print = old_print
    return catstr

list = ["print('Wow!')\n", "print('Great!')\n", "print('Epic!')\n"]

print (execute(list))

你所需要的只是非本地并忘记你创建的所有其他变量bar catstr:

def execute(lst):
    def print(s):
        nonlocal catstr
        catstr += s
    catstr = ""
    for item in lst:
        s = item
        exec(s)
    return catstr

这给你:

In [1]: paste
def execute(lst):
    def print(s):
        nonlocal catstr
        catstr += s
    catstr = ""
    for item in lst:
        s = item
        exec(s)
    return catstr

## -- End pasted text --

In [2]: list = ["print('Wow!')\n", "print('Great!')\n", "print('Epic!')\n"]

In [3]: execute(lst)
Out[3]: 'Wow!Great!Epic!'

函数中发生的任何事情都是函数的局部,因此您无需担心重置任何内容。如果您碰巧想要设置打印参考,您可以使用 old_print = __builtins__.print.

如果你想在不需要打印调用的情况下打印函数,请使用 __builtins__.print 进行打印:

def execute(lst):
    catstr = ""
    def print(s):
        nonlocal catstr
        catstr += s
    for s in lst:
        exec(s)
    __builtins__.print(catstr)

Prune 和 Padraic Cunningham 的回答已经解决了您的问题,这是实现(我猜)您想要的另一种方法:

import io
from contextlib import redirect_stdout

g_list = ["print('Wow!')\n", "print('Great!')\n", "print('Epic!')\n"]


def execute(lst):
    with io.StringIO() as buf, redirect_stdout(buf):
        [exec(item) for item in lst]
        return buf.getvalue()


def execute_modified(lst):
    result = []
    for item in lst:
        with io.StringIO() as buf, redirect_stdout(buf):
            exec(item)
            result.append(buf.getvalue()[:-1])

    return "".join(result)


print(execute(g_list))
print('-' * 80)
print(execute_modified(g_list))

输出:

Wow!
Great!
Epic!

--------------------------------------------------------------------------------
Wow!Great!Epic!