重新定义打印功能在功能中不起作用

时间:2016-09-13 23:57:42

标签: python function printing exec

我正在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

有谁知道为什么这不能在功能中使用?
任何有关如何修复它的建议都将受到高度赞赏。

3 个答案:

答案 0 :(得分:2)

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

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))

答案 1 :(得分:2)

您只需要非本地并忘记您创建的所有其他变量吧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)

答案 2 :(得分:1)

你的问题已经由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!