2016-09-13 1 views
1

J'écris un script python dans python 3.x dans lequel j'ai besoin de redéfinir la fonction print. Quand je le fais avec mon interprète, ça fonctionne bien. Mais quand je crée une fonction en utilisant le même code, cela donne une erreur.Redéfinition de la fonction d'impression ne fonctionnant pas dans une fonction

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

Comme vous pouvez le voir, je l'ai obtenu mon résultat souhaité: 'Wow!Great!Epic!'

Maintenant, je fais une fonction en utilisant le même code:

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 

maintenant lorsque j'exécute cette fonction en utilisant le code suivant:

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

execute(list) 

J'obtiens l'erreur suivante:

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

Est-ce que quelqu'un sait pourquoi cela ne fonctionne pas dans une fonction?
Toutes les suggestions sur la façon de le réparer seront très appréciées.

+0

C'est la première ligne comme vous définissez l'impression dans la fonction et en tant que fonction, qu'est-ce que vous utilisez old_print etc .. du tout? –

+1

Quel est le but de votre question? Ou est-ce juste par curiosité? – BPL

+0

@BPL Il est directement lié comme une question de suivi, ils ont demandé hier [ici] (http://stackoverflow.com/questions/39460882/how-to-get-execution-of-python-print-statements-as-a -string) – idjaw

Répondre

2

Tout ce que vous avez besoin est nonlocal et d'oublier toutes les autres variables que vous avez créées bar catstr:

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

Cela vous donne:

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

Tout ce qui se passe dans le La fonction est locale à la fonction afin que vous n'ayez pas à vous soucier de réinitialiser quoi que ce soit. Si vous vouliez définir une référence à imprimer, vous pouvez utiliser old_print = __builtins__.print.

Si vous voulez avoir votre impression fonction sans avoir besoin un appel d'impression __builtins__.print faire l'impression:

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

Merci! Cela a fonctionné :) – Elisha512

+0

Pas de soucis, j'ai ajouté une variation qui se comporte comme impression c'est-à-dire qu'elle renvoie Aucun et imprime juste –

2

L'interpréteur ne reconnaît pas comme comme fonction intégrée à moins que vous ne le disiez spécifiquement. Au lieu de le déclarer global, il suffit de le supprimer (grâce à Padraic Cunningham): le imprimer prendra votre définition désirée, et le global n'est jamais affecté.

Vous avez également un problème de référence vers l'avant avec catstr. Le code ci-dessous provoque la sortie désirée.

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

Juste en supprimant 'old_print = print' etc .. vous donnerait la même sortie exacte –

+1

Droit! Le ** print ** local n'affecte pas le built-in. – Prune

1

Votre question a déjà été abordée par des réponses Taillez et Padraic Cunningham, voici une autre alternative pour atteindre (je suppose) ce que vous voulez:

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

sortie:

Wow! 
Great! 
Epic! 

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

Cela met toutes les données sur des lignes différentes, le * résultat souhaité est "Wow! Great! Epic!" –

+0

@PadraicCunningham Tu m'as eu là: P. J'ai édité ma réponse ... Bien que je ne sois pas très content de la solution que j'ai trouvée, des suggestions sont les bienvenues – BPL