Intrygujący problem! Domyślam się, że sys.stdout.write
nie wywołuje metody __str__
, ponieważ Twój obiekt już jest jest a str
(lub przynajmniej jego podklasa, która jest wystarczająco dobra dla wszystkich celów i celów) ... więc nie są potrzebne żadne metody rzutowania .
Dalsze badania sugerują, że sys.stdout.write
naprawdę nie zawsze chcą wywołać metodę __str__
...
podejście Podklasa
Przy odrobinie introspekcji, można dowiedzieć się, jakie metody swojej str
podklasy są nazywany przez sys.stdout.write
(odpowiedź brzmi, nie wiele):
class superstring(str):
def __getattribute__(self, name):
print "*** lookup attribute %s of %s" % (name, repr(self))
return str.__getattribute__(self, name)
foo = superstring("UberL33tPrompt> ")
sys.stdout.write(foo)
bieganie w Enviro Unicode nment (Python 2.7, ipython notebook), to drukuje:
*** lookup attribute __class__ of 'UberL33tPrompt> '
*** lookup attribute decode of 'UberL33tPrompt> '
UberL33tPrompt>
Wydaje się raczej kludge-y, ale można zastąpić podklasy za decode
metodę wykonywania pożądanych efektów ubocznych.
Jednak w środowisku innym niż Unicode nie ma wyszukiwania atrybutów.
podejście Wrapper
Zamiast używać podklasę str
, może to, czego potrzebujesz to pewnego rodzaju „wrapper” wokół str
. Oto brzydki rozpoznawcza siekać który tworzy klasę, która przekazuje większość jego atrybutów do str
, ale który nie jest ściśle ich podklasy:
class definitely_not_a_string(object):
def __init__(self, s):
self.s = s
def __str__(self):
print "*** Someone wants to see my underlying string object!"
return self.s
def decode(self, encoding, whatever):
print "*** Someone wants to decode me!"
return self.s.decode(encoding, whatever)
def __getattribute__(self, name):
print "*** lookup attribute %s of %s" % (name, repr(self))
if name in ('s', '__init__', '__str__', 'decode', '__class__'):
return object.__getattribute__(self, name)
else:
return str.__getattribute__(self, name)
foo = definitely_not_a_string("UberL33tPrompt> ")
sys.stdout.write(foo)
W środowisku Unicode, co daje w zasadzie te same wyniki:
*** lookup attribute __class__ of <__main__.definitely_not_a_string object at 0x00000000072D79B0>
*** lookup attribute decode of <__main__.definitely_not_a_string object at 0x00000000072D79B0>
*** Someone wants to decode me!
*** lookup attribute s of <__main__.definitely_not_a_string object at 0x00000000072D79B0>
UberL33tPrompt>
jednak, kiedy uruchamiane w środowisku innym niż Unicode, definitely_not_a_string
daje komunikat o błędzie:
TypeError: expected a character buffer object
... to s hows, że metoda .write
przechodzi bezpośrednio na poziom C buffer interface, kiedy nie trzeba wykonywać żadnego dekodowania Unicode.
Mój wniosek
Wydaje się, że przesłanianie metody decode
jest możliwe kludge w środowisku Unicode, ponieważ sys.stdout.write
wywołania tej metody musi dekodować str
do Unicode.
Jednak w środowiskach nieobsługujących kodu Unicode wydaje się, że .write
nie wykonuje żadnych wyszukiwań atrybutów, ale po prostu przechodzi bezpośrednio do protokołu buforowania znaków na poziomie C, więc nie ma możliwości przechwycenia jego dostępu z kodu Pythona. Rzeczywiście, help(sys.stdout.write)
weryfikuje, czy jest to funkcja wbudowana (napisana w C, nie w Pythonie).
To interesujący pomysł. Zastanawiam się, czy naprawdę zrobiłbym to, co chcę ... Jest wiele naprawdę fajnych rzeczy, które można łatwo modyfikować zachowanie standardowego REPL, jeśli to zadziała. Zajmę się tym później wieczorem i dam ci znać, czy zadziała, czy nie (i zaakceptuję twoją odpowiedź, jeśli to zadziała). – ArtOfWarfare
+1 Ben: Działa to w odpowiedzi na pytanie, które zadałem, ale niestety nie wykrywa, kiedy sys.ps2 jest drukowane. – ArtOfWarfare
Możesz po prostu sprawdzić, czy "jeśli jest sys.ps2" – Ben