2009-08-07 7 views
2

Grundsätzlich möchte ich Zugriff auf alle Standard-Python-Int-Operatoren haben, zB __and__ und __xor__ etc, speziell wann immer das Ergebnis gedruckt wird Ich möchte es im Hex-Format dargestellt. (Art wie mein Rechner in Hex-Modus versetzen)Unterklasse int, um eine Hex-Darstellung zu erhalten

class Hex(int): 
    def __repr__(self): 
    return "0x%x"%self 
    __str__=__repr__ # this certainly helps with printing 

if __name__=="__main__": 
    print Hex(0x1abe11ed)^Hex(440720179) 
    print Hex(Hex(0x1abe11ed)^Hex(440720179)) 

Im Idealfall sollten BEIDE Zeilen der Ausgabe hexadezimal sein: 0xfacade jedoch die erste ergibt dezimal: 16435934

Irgendwelche Ideen?

+1

Warum nicht einfach die eingebaute Funktion 'hex()' verwenden? http://docs.python.org/library/functions.html#hex –

+1

Das Einfügen von hex() in die zahlreichen verschiedenen Stellen wäre zeitraubend und ungenau. Das Umschalten der Darstellung für alles vom Typ Hex (int) wäre ein einfacher Refactor. Allerdings: Ich denke, man muss alle hexadezimalen dyadischen Operatoren überladen, um auch ein Hex-Ergebnis zurückzugeben (momentan liefern sie immer noch int). Vielleicht gibt es ein "Mixin" zum Überladen von Betreibern in großen Mengen. –

Antwort

1

Als Antwort auf Ihren Kommentar:

Sie einen Mixin selbst schreiben können:

class IntMathMixin: 
    def __add__(self, other): 
     return type(self)(int(self).__add__(int(other))) 
    # ... analog for the others 

Dann ist es wie folgt verwenden:

class Hex(IntMathMixin, int): 
    def __repr__(self): 
     return "0x%x"%self 
    __str__=__repr__ 
+0

Warum wurde die Mixin-Lösung gegenüber einer einfachen Unterklasse gemäß der Antwort von @Greg Hewgill bevorzugt? –

0

Überschreiben Sie auch __str__.

__repr__ wird verwendet, wenn repr (o) aufgerufen wird, und um einen Wert an der interaktiven Eingabeaufforderung anzuzeigen. __str__ wird für die meisten Instanzen aufgerufen, um ein Objekt zu stringieren, auch wenn es gedruckt wird.

Der Standard __str__ Verhalten für ein Objekt ist an die repr fallen zurück, aber int stellt eine eigene __str__ Methode (die __repr__ identisch ist (vor Python 3), funktioniert aber nicht fallen zurück-__repr__).

7

Sie sollten __repr__ und __str__ separat definieren:

class Hex(int): 
    def __repr__(self): 
    return "Hex(0x%x)" % self 
    def __str__(self): 
    return "0x%x" % self 

Die __repr__ Funktion zur Verfügung stellen soll Text Python (wenn möglich), die eval() uated sein kann, das ursprüngliche Objekt zu rekonstruieren. Auf der anderen Seite kann __str__ nur eine menschenlesbare Darstellung des Objekts zurückgeben.

+0

Prost für die Unterscheidung zwischen __str__ und __repr__. –

+1

Da repl (23) und str (23) genau den gleichen Ergebnisstring liefern, würde ich nicht besonders heiß und belästigt werden über eine Unterklasse von int, die das auch tut - wenn Hex in einem Modul ist, wissen Sie nie, ob return 'Hex (0x0)' oder 'themodule.Hex (0x0)' (da Sie nicht wissen, wie der Import ausgedrückt wurde!), so ist die 'eval'-Fähigkeit des Strings trotzdem ziemlich unpassend (' __import __ ('themodule ') .Hex (0x0) 'ist breiter auswertbar, für Module, die nicht in Unterpaketen sind, aber wenn ich gesehen habe, dass von' __repr__' in einem Code-Review zurückgekehrt ist, würde ich das Änderungsset einreichen! -). –

+0

Ich halte '__repr__' eine Art Best-Effort-Sache wirklich. Offensichtlich kann es nicht in allen Fällen das Richtige tun. –

1

Sie müssen die Operatoren (+, -, ** usw.) dazu bringen, Hex-Instanzen zurückzugeben. Wie wird es Ints zurückkehren, dh

class Hex(int): 
    def __repr__(self): 
     return "Hex(0x%x)" % self 
    def __str__(self): 
     return "0x%x" % self 
>>> h1 = Hex(100) 
>>> h2 = Hex(1000) 
>>> h1 
Hex(0x64) 
>>> h2 
Hex(0x3e8) 
>>> h1+h2 
1100 
>>> type(h1+h2) 
<type 'int'> 

So können Sie die verschiedenen Operatoren außer Kraft setzen:

class Hex(int): 
    def __repr__(self): 
     return "Hex(0x%x)" % self 
    def __str__(self): 
     return "0x%x" % self 
    def __add__(self, other): 
     return Hex(super(Hex, self).__add__(other)) 
    def __sub__(self, other): 
     return self.__add__(-other) 
    def __pow__(self, power): 
     return Hex(super(Hex, self).__pow__(power)) 
    def __xor__(self, other): 
     return Hex(super(Hex, self).__xor__(other)) 

>>> h1 = Hex(100) 
>>> h2 = Hex(1000) 
>>> h1+h2 
Hex(0x44c) 
>>> type(h1+h2) 
<class '__main__.Hex'> 
>>> h1 += h2 
>>> h1 
Hex(0x44c) 
>>> h2 ** 2 
Hex(0xf4240) 
>>> Hex(0x1abe11ed)^Hex(440720179) 
>>> Hex(0xfacade) 

ich darüber weiß es nicht, ich glaube, dass es einen besseren Weg, ohne muss jeder Operator überschreiben, um eine Instanz von Hex zurückzugeben ???

6

A Klasse Dekorateur, vor allem in Python 2.6 und darüber hinaus ist der einfachste Weg, eine Vielzahl von Methoden zu "umwandeln", um eine Instanz dieses Klassestyps anstelle einer Instanz des Super zurückzugeben Klasse ", die, wie andere angegeben haben, Ihr zugrunde liegendes Problem ist (abgesehen von Quatsch mit __str__ vs __repr__, lohnend, aber überhaupt nicht auflösend für Ihr Problem ;-).

def returnthisclassfrom(specials): 
    specialnames = ['__%s__' % s for s in specials.split()] 
    def wrapit(cls, method): 
    return lambda *a: cls(method(*a)) 
    def dowrap(cls): 
    for n in specialnames: 
     method = getattr(cls, n) 
     setattr(cls, n, wrapit(cls, method)) 
    return cls 
    return dowrap 

@returnthisclassfrom('and or xor') 
class Hex(int): 
    def __repr__(self): return hex(self) 
    __str__ = __repr__ 

a = Hex(2345) 
b = Hex(5432) 
print a, b, a^b 

In Python 2.6, dies emittiert

0x929 0x1538 0x1c11 

wie gewünscht. Natürlich können Sie dem Dekorator weitere Methodennamen hinzufügen, usw .; wenn Sie mit Python 2.5 stecken, entfernen Sie die Dekoration Linie (die mit @ Start) und stattdessen

class Hex(int): 
    def __repr__(self): return hex(self) 
    __str__ = __repr__ 
Hex = returnthisclassfrom('and or xor')(Hex) 

eine Milbe weniger elegant, aber genauso effektiv ;-)

bearbeiten verwenden: ein "normales Problem" im Code behoben.

+0

+1. Ich wusste, dass es eine einfachere Lösung geben muss. Aber ich wusste nicht, dass man Dekoratoren für Klassen verwenden kann. Danke. – Ralph

+0

@Ralph, herzlich willkommen! Decorator Syntax wird nur seit Python 2.6 unterstützt, aber ich habe auch gezeigt, wie ein Dekorator (mit weniger elegante Syntax) auf eine Klasse in älteren Python verwendet werden kann (zB 2.5, mit denen Sie stecken in Google App Engine zum Beispiel, oder als das vom System bereitgestellte Python mit MacOSX und vielen Linux-Distributionen usw. ;-). –

+0

Es stimmt etwas nicht (zumindest in Python 2.5), wo der letzte Methodenname in specials auch für alle vorhergehenden Methoden verwendet wird, z. 'drucke a, b, a und b, a | b, a^b >>> 0x929 0x1538 0x1c11 0x1c11 0x1c11', aber es sollte' 0x929 0x1538 0x128 0x1d39 0x1c11' sein. – mhawke