3 Stimmen

Wie kann man eine Klasse erstellen, die sich wie eine Zeichenkette verhält?

Ich habe einen Kontext-Manager, die Ausgabe in eine Zeichenfolge für einen Block von Code unter einem eingerückt erfasst with Erklärung. Dieser Kontextmanager liefert ein benutzerdefiniertes Ergebnisobjekt, das nach Beendigung der Ausführung des Blocks die erfasste Ausgabe enthält.

from contextlib import contextmanager

@contextmanager
def capturing():
    "Captures output within a 'with' block."
    from cStringIO import StringIO

    class result(object):
        def __init__(self):
            self._result = None
        def __str__(self):
            return self._result

    try:
        stringio = StringIO()
        out, err, sys.stdout, sys.stderr = sys.stdout, sys.stderr, stringio, stringio
        output = result()
        yield output
    finally:
        output._result, sys.stdout, sys.stderr = stringio.getvalue(), out, err
        stringio.close()

with capturing() as text:
    print "foo bar baz",

print str(text)   # prints "foo bar baz"

Ich kann natürlich nicht einfach eine Zeichenkette zurückgeben, weil Zeichenketten unveränderlich sind und somit die, die der Benutzer von der with Anweisung kann nicht mehr geändert werden, nachdem ihr Codeblock ausgeführt wurde. Allerdings ist es etwas umständlich, das Ergebnisobjekt im Nachhinein explizit in eine Zeichenkette umzuwandeln mit str (Ich habe auch damit gespielt, das Objekt aufrufbar zu machen, um die Syntax zu verbessern).

Ist es also möglich, das Ergebnis Instanz handeln wie eine Zeichenfolge, in der es in der Tat eine Zeichenfolge zurück, wenn benannt? Ich habe versucht zu implementieren __get__ aber das scheint nur bei Attributen zu funktionieren. Oder ist das, was ich tun möchte, nicht wirklich möglich?

0 Stimmen

Unabhängig davon, ob es eine Antwort auf diese Frage gibt oder nicht, würde ich es vorziehen, eine Klasse zurückzugeben, die __str__ . Ich bin mir nicht sicher, inwiefern es ein Hindernis ist, dass man an einem bestimmten Punkt explizit sagen muss: "Genau hier ist der Punkt, an dem ich dies als String festhalte, keine weiteren Änderungen", indem man str() . Was ist also der Gewinn?

0 Stimmen

@Mike: Hauptsächlich, dass ein Benutzer die Zeichenkette will, nicht ein Objekt, das in eine Zeichenkette umgewandelt werden muss.

0 Stimmen

Es sieht so aus, als ob UserString (naja, MutableString, aber das geht weg) im Grunde das ist, was ich will, also werde ich dafür stimmen, dies zu schließen. Bearbeiten: Hoppla, ich schätze, ich kann das nicht wirklich tun, da keiner der Gründe wirklich zutreffen.

0voto

PyGuy Punkte 291

Dies ist eine alte, aber interessante Frage. Mit der Idee von @S.Lott können Sie Kontextmanager verwenden, um ein robusteres und wiederverwendbares Werkzeug zu erstellen:

@contextmanager
def redefine_print(stream):
    global print
    from functools import partial, wraps
    old_print = print
    try:
        print = wraps(print)(partial(print, file=stream))
        yield print
    finally:
        print = old_print

Beispiel für die Verwendung mit dateiähnlichen Objekten:

with open('file', 'a+') as stream:
    print('a')       # print in the interface
    with redefine_print(stream):
        print('b')   # print in the file 
    print('c')       # print in the interface
    stream.seek(0)
    print(stream.readlines())

Beispiel für die Verwendung mit StringIO-Objekten

import io
stream = io.StringIO()
with redefine_print(stream) as xprint:
    print('b')   # add to the ioStream
    xprint('x')   # same as print, just to see how the object works

print(stream.getvalue())   # print the intercepted value
print(xprint.__doc__)      # see how @wraps helps to keep print() signature

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X