2009-08-07 2 views
2

В принципе, я хочу иметь доступ ко всем стандартным операторам int python, например __and__ и __xor__ и т. Д., Особенно когда результат окончательно напечатан. Я хочу, чтобы он представлялся в формате Hex. (Вроде как положить мой калькулятор в режим Hex)subclassing int, чтобы получить представление Hex

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

В идеале ОБА строка вывода должна быть шестнадцатеричной: 0xfacade, однако первые один дает десятичное: 16435934

Любые идеи?

+1

Почему бы просто не использовать встроенную функцию 'hex()'? http://docs.python.org/library/functions.html#hex –

+1

Вставка hex() в многочисленные различные подходящие места будет трудоемкой и неточной. Переключение представления для чего-либо типа Hex (int) было бы простым рефактором. Однако: я думаю, что нужно перегрузить все дескрипторы Hex/int, чтобы вернуть результат Hex (в настоящее время они все еще дают int). Может быть, есть «Mixin» для перегрузки операторов навалом. – 2009-08-07 03:12:37

ответ

1

В ответ на ваш комментарий:

Вы можете написать подмешать сами:

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

затем использовать его как это:

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

Почему раствор миксина предпочтительнее простого подкласса в соответствии с ответом @Greg Hewgill? –

0

Переопределение __str__ также.

__repr__ используется, когда вызывается функция repr (o), и отображает значение в интерактивном приглашении. __str__ вызывается для большинства случаев строения объекта, в том числе при его печати.

__str__ поведения по умолчанию для объекта, чтобы возвратиться к repr, но int предоставляет свой собственный __str__ метод (который идентичен __repr__ (до Python 3), но не падения назад к __repr__).

7

Вы должны определить __repr__ и __str__ отдельно:

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

__repr__ функция должна (если это возможно) предоставить Python текст, который может быть eval() закончил институт, чтобы восстановить исходный объект. С другой стороны, __str__ может просто вернуть читаемое человеком представление объекта.

+0

Приветствия за различие между __str__ и __repr__. – 2009-08-07 03:21:53

+1

Так как репрессия (23) и str (23) дают точно такую ​​же строку результата, я бы не стал особенно жарким и беспокоился о том, что подкласс int также делает это - ведь если Hex находится в модуле, вы никогда не знаете, return 'Hex (0x0)' или 'themodule.Hex (0x0)' (так как вы не знаете, как был выражен импорт!), поэтому способность 'eval' строки в любом случае довольно iffy (' __import __ ('themodule ') .Hex (0x0) 'более широко оценивается, для модулей, не входящих в подпакеты, но если бы я увидел, что THAT вернулся из' __repr__' в обзоре кода, я бы наложил вето на внесение набора изменений! -). –

+0

Я считаю, что «__repr__» - это нечто вроде всего хорошего. Очевидно, что во всех случаях это не может делать правильно. –

1

Вам нужно будет получить операторы (+, -, ** и т. Д.), Чтобы возвращать экземпляры Hex. Как, он будет возвращать Интс, т.е.

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

Таким образом, вы можете изменить различные операторы:

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) 

я не знаю об этом, я чувствую, что должен быть лучший способ без чтобы переопределить каждый оператор, чтобы вернуть экземпляр Hex ???

6

класс декоратора, особенно в Python 2.6 и выше, это самый удобный способ обернуть множество методов, чтобы «вернуть экземпляр типа этого класса, а не экземпляр супер класс ", который, как указывали другие, является вашей основной проблемой (помимо quibbles с __str__ vs __repr__, стоит, но совсем не решительно для вашей проблемы ;-).

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 

В Python 2.6, это испускает

0x929 0x1538 0x1c11 

как пожелал. Конечно, вы можете добавить дополнительные имена методов в декоратор и т. Д .; если вы застряли с Python 2.5, снимите украшения линии (один, начиная с @) и использовать вместо

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

клещ менее элегантно, но столь же эффективным ;-)

Edit: зафиксировано появление «обычного вопроса» в коде.

+0

+1. Я знал, что должно быть более простое решение. Но я не знал, что можно использовать декораторы на классах. Спасибо. – Ralph

+0

@ Ральф, добро пожаловать! синтаксис конструктора поддерживается только с python 2.6, но я также показал, как декоратор (с менее элегантным синтаксисом) можно использовать для класса в более раннем python (например, 2.5, с которым вы застряли в Google app engine, например, или как системный Python с MacOSX и многими дистрибутивами Linux и т. д .;-). –

+0

В этом есть что-то не так (по крайней мере, на Python 2.5), где последнее имя метода в специальностях также используется для всех предыдущих методов, например. 'print a, b, a & b, a | b, a^b >>> 0x929 0x1538 0x1c11 0x1c11 0x1c11', но это должно быть' 0x929 0x1538 0x128 0x1d39 0x1c11'. – mhawke

Смежные вопросы