子类化int以获取十六进制表示
基本上,我想使用所有标准的 Python 整数运算符,比如 __and__
和 __xor__
等等,特别是当结果最终被打印出来时,我希望它以十六进制格式显示。(有点像把我的计算器切换到十六进制模式)
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
有什么想法吗?
5 个回答
6
一个类装饰器,特别是在Python 2.6及以后的版本中,是一种非常方便的方法,可以把很多方法包装起来,让它们“返回这个类的实例,而不是返回父类的实例”。这正是你面临的主要问题(当然,还有一些关于__str__
和__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)
虽然这样稍微不那么优雅,但效果一样好;-)
编辑:修正了代码中出现的“常见作用域问题”。
7
你应该分别定义 __repr__
和 __str__
:
class Hex(int):
def __repr__(self):
return "Hex(0x%x)" % self
def __str__(self):
return "0x%x" % self
__repr__
这个函数应该(如果可能的话)提供一段可以用 eval()
来重新创建原始对象的 Python 代码。另一方面,__str__
则可以返回一个人类可读的对象表示形式。
1
针对你的评论:
你可以自己写一个混合类(Mixin):
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__