2016-09-13 5 views
1

Ich schreibe ein Python-Skript in Python 3.x, in dem ich die print-Funktion neu definieren muss. Wenn ich es in meinem Dolmetscher mache, funktioniert es gut. Aber wenn ich eine Funktion unter Verwendung des gleichen Codes erstelle, gibt es einen Fehler aus.Redefining Druckfunktion funktioniert nicht innerhalb einer Funktion

Hier ist mein Code:

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!' 

Wie Sie habe ich meine gewünschte Ergebnis sehen bekam: 'Wow!Great!Epic!'

Jetzt habe ich eine Funktion mit dem gleichen Code machen:

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 

Jetzt Wenn ich diese Funktion unter Verwendung des folgenden Codes ausfühle:

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

execute(list) 

Ich erhalte die folgende Fehlermeldung:

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

Weiß jemand, warum dies in einer Funktion nicht funktioniert?
Alle Vorschläge, wie Sie es beheben können, werden sehr geschätzt.

+0

Es ist die erste Zeile, wie Sie Print in der Funktion definieren und als Funktion, was benutzen Sie old_print etc .. überhaupt? –

+1

Was ist der Zweck Ihrer Frage? Oder ist das nur aus Neugier? – BPL

+0

@BPL Es ist direkt als Folgefrage verwandt, die sie gestern [hier] (http://stackoverflow.com/questions/39460882/how-to-get-execution-of-python-print-statements-as-a) gefragt haben -string) – idjaw

Antwort

2

Alles, was Sie brauchen, ist nonlocal und alle anderen Variablen vergessen Sie bar angelegt haben catstr:

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

Das gibt Ihnen:

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!' 

Alles, was in der geschieht, Funktion ist lokal für die Funktion, so dass Sie sich keine Gedanken über das Zurücksetzen von irgendetwas machen müssen. Wenn Sie einen Verweis auf den Druck festlegen möchten, können Sie old_print = __builtins__.print verwenden.

Wenn Sie Ihre Funktion Druck haben wollen, ohne einen Druck Anruf Verwendung zu benötigen __builtins__.print den Druck zu tun:

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

Danke! Es hat funktioniert :) – Elisha512

+0

Keine Sorge, ich habe eine Variante hinzugefügt, die sich wie Drucken verhält, dh es gibt keine zurück und druckt nur –

2

Der Interpreter erkennt nicht Drucken als die integrierte Funktion, es sei denn, Sie sagen es ausdrücklich. Anstatt es global zu deklarieren, entferne es einfach (danke an Padraic Cunningham): das lokale print wird deine gewünschte Definition annehmen, und das Globale wird niemals beeinflusst.

Sie haben auch ein Vorwärtsreferenzproblem mit cattr. Der folgende Code ruft die gewünschte Ausgabe hervor.

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

Das Entfernen von 'old_print = print' etc .. würde Ihnen genau die gleiche Ausgabe geben –

+1

Richtig! Der lokale ** Druck ** hätte keinen Einfluss auf das eingebaute System. – Prune

1

Ihr Problem bereits von Prune und Padraic Cunningham Antworten angesprochen wurde, hier ist eine andere alternative Art und Weise zu erreichen, (i guess), was Sie wollen:

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

Ausgang:

Wow! 
Great! 
Epic! 

-------------------------------------------------------------------------------- 
Wow!Great!Epic! 
+0

Das bringt alle Daten auf verschiedene Zeilen, das * gewünschte Ergebnis * ist ''Wow! Great! Epic!'' –

+0

@PadraicCunningham Du hast mich da: P. Ich habe meine Antwort bearbeitet ... Obwohl ich mit der Lösung, die ich mir ausgedacht habe, nicht sehr zufrieden bin, wurden Vorschläge begrüßt – BPL

Verwandte Themen