2009-02-15 14 views
35

Czy jestem w stanie przeciążyć funkcję print i wywołać normalną funkcję od wewnątrz? Chcę, aby po konkretnej linii potrzebowałem print zadzwonić na mój numer print, który wywoła normalny numer print i zapisze kopię do pliku.Przeciążenie wydruku python

Również nie wiem, jak przeciążyć print. Nie wiem jak robić argumenty o zmiennej długości. Niedługo to sprawdzę, ale overload print python powiedział mi, że nie mogę przeciążać print w 2.x której używam.

Odpowiedz

2

W języku Python 2.x nie można, ponieważ druk nie jest funkcją, jest to instrukcja. W Pythonie 3 print jest funkcją, więc przypuszczam, że można ją przesłonić (chociaż jej nie próbowałem).

31

Przeciążanie print to funkcja projektowania Pythona 3.0, która rozwiązuje problem braku możliwości zrobienia tego w python 2.x.

Można jednak zastąpić sys.stdout. (example.) Po prostu przypisz go do innego obiektu podobnego do pliku, który robi to, co chcesz.

Alternatywnie można po prostu przesłać skrypt za pomocą polecenia unix tee. python yourscript.py | tee output.txt będzie drukować zarówno na standardowe wyjście, jak i na output.txt, ale spowoduje to przechwycenie wszystkich danych wyjściowych.

3

Chociaż nie można zastąpić słowa kluczowego print (w Pythonie 2.x print jest kluczowe), jest to powszechna praktyka, aby zastąpić sys.stdout zrobić coś podobnego do print nadrzędnego; na przykład z instancją StringIO.StringIO. Spowoduje to przechwycenie wszystkich wydrukowanych danych w instancji StringIO, po czym można nimi manipulować.

10

Natrafiłem na ten sam problem.

Jak o tym:

class writer : 
    def __init__(self, *writers) : 
     self.writers = writers 

    def write(self, text) : 
     for w in self.writers : 
      w.write(text) 

import sys 

saved = sys.stdout 
fout = file('out.log', 'w') 
sys.stdout = writer(sys.stdout, fout) 
print "There you go." 
sys.stdout = saved 
fout.close() 

To działało jak urok dla mnie. Został zabrany z http://mail.python.org/pipermail/python-list/2003-February/188788.html

+3

'saved = sys.stdout' jest niepotrzebne,' sys .__ stdout__' zawsze zawiera oryginalne 'stdout', więc na końcu wystarczy' sys.stdout = sys .__ stdout__'. – chown

+0

zapisywanie sys.stdout umożliwia przesłonięcie łańcucha; jeśli napiszesz bezpośrednio do sys .__ stdout__ pominiesz jakiekolwiek struktury logowania lub takie, które spróbujesz i wstrzykniesz do programu. Najlepiej jawnie zapisać poprzednią wartość stdout. – Will

+0

Czy istnieje szczególny powód, dla którego otwierasz dziennik za pomocą 'file()' zamiast 'open()'? [Dokumentacja tego zaleca.] (Https://docs.python.org/2/library/functions.html#file) – Eric

1

Odpowiedziałem samo pytanie on a different SO question

Zasadniczo, najprostszym rozwiązaniem jest po prostu przekierować wyjście na stderr w następujący sposób, w pliku konfiguracyjnym WSGI.

sys.stdout = sys.stderr 
50

Dla osób, które przeglądały wcześniej opatrzone datą odpowiedzi, od wydania wersji "Python 2.6" jest nowa odpowiedź na oryginalne pytanie z plakatu.

W Pythonie 2.6 iw górę, można wyłączyć oświadczenie druku na korzyść funkcji drukowania, a następnie zastąpić funkcję drukowania z własnej funkcji druku:

from __future__ import print_function 
# This must be the first statement before other statements. 
# You may only put a quoted or triple quoted string, 
# Python comments, other future statements, or blank lines before the __future__ line. 

try: 
    import __builtin__ 
except ImportError: 
    # Python 3 
    import builtins as __builtin__ 

def print(*args, **kwargs): 
    """My custom print() function.""" 
    # Adding new arguments to the print function signature 
    # is probably a bad idea. 
    # Instead consider testing if custom argument keywords 
    # are present in kwargs 
    __builtin__.print('My overridden print() function!') 
    return __builtin__.print(*args, **kwargs) 

Oczywiście trzeba rozważyć że ta funkcja drukowania jest w tym momencie tylko modułem. Możesz zastąpić __builtin__.print, ale musisz zapisać oryginalny __builtin__.print; prawdopodobnie mucking z przestrzeni nazw __builtin__.

+0

Jeśli spróbuję użyć tej funkcji w Pythonie 2.7.3, otrzymam 'linię 7, w druku return __builtins __. Print (* args, ** kwargs) AttributeError: Obiekt 'dict' nie ma atrybutu "print'' error. Jaki może być problem? – loudandclear

+0

Hmmm ... Testowałem to z Pythonem 2.7.2 i działało. Zauważyłem, że właśnie wydano Python 2.7.4 i jest kilka poprawek z _ _future _ _ i print_function Sprawdź http://hg.python.org/cpython/file/9290822f2280/Misc/NEWS Nie testowałem 2.7.4. – DevPlayer

+2

Powinieneś zrobić 'import __builtin__', a następnie' __builtin __. Print' zamiast używać '__builtins__', [patrz wyjaśnienie tutaj] (https://docs.python.org/2/reference/executionmodel.html). – rczajka

8
class MovieDesc: 
    name = "Name" 
    genders = "Genders" 
    country = "Country" 

def __str__(self): 
#Do whatever you want here 
     return "Name: {0}\tGenders: {1} Country: {2} ".format(self.name,self.genders,self.country) 

) 
1

tylko myślałem, że dodam mój pomysł ...odpowiadał moim celom, aby móc uruchomić sthg w Eclipse, a następnie uruchomić z CLI (Windows) bez uzyskiwania wyjątków kodowania z każdym poleceniem print. Cokolwiek robisz, nie czynisz klasy EncodingStdout podklasą pliku klasy: wiersz "self.encoding = encoding" spowodowałby, że atrybut encoding był None!

NB Jedną rzeczą, którą dowiedziałem się w ciągu dnia, zmagając się z tym problemem jest to, że wyjątek kodowania zostaje podniesiony PRZED uzyskaniem "drukowania" lub "zapisu": to jest, gdy sparametryzowany ciąg znaków (np. "Mondodod% s blah blah%" s "% (" blip "," blap ")) jest zbudowany przez ... co ??? ramy"?

class EncodingStdout(object): 
    def __init__(self, encoding='utf-8'): 
     self.encoding = encoding 

    def write_ln(self, *args): 
     if len(args) < 2: 
      sys.__stdout__.write(args[ 0 ] + '\n') 
     else: 
      if not isinstance(args[ 0 ], basestring): 
       raise Exception("first arg was %s, type %s" % (args[ 0 ], type(args[ 0 ]))) 
      # if the default encoding is UTF-8 don't bother with encoding 
      if sys.getdefaultencoding() != 'utf-8': 
       encoded_args = [ args[ 0 ] ] 
       for i in range(1, len(args)): 
        # numbers (for example) do not have an attribute "encode" 
        if hasattr(args[ i ], 'encode'): 
         encoded_args.append(args[ i ].encode(self.encoding, 'replace')) 
        else: 
         encoded_args.append(args[ i ]) 
       args = encoded_args 
      sys.__stdout__.write(args[ 0 ] % tuple(args[ 1 : ]) + '\n') 
     # write seems to need a flush 
     sys.__stdout__.flush() 

    def __getattr__(self, name): 
     return sys.__stdout__.__getattribute__(name) 

print "=== A mondodod %s %s" % ("été", "pluviôse, irritée contre la ville entière") 


sys.stdout = EncodingStdout() 
sys.stdout.write_ln("=== B mondodod %s %s", "été", "pluviôse, irritée contre la ville entière") 

# convenience method 
def pr(*args): 
    sys.stdout.write_ln(*args) 

pr("=== C mondodod %s %s", "été", "pluviôse, irritée contre la ville entière") 
1

Dla bardzo prosty przykład, jak z Python3.4 (nie testowałem ze starszymi wersjami) to działa dobrze dla mnie (umieszczony na górze modułu):

def dprint(string): 
    __builtins__.print("%f -- %s" % (time.time(), string)) 

print = dprint 

Uwaga ta działa tylko wtedy, gdy parametr string jest znakiem ... YMMV