子类化int以获取十六进制表示

2 投票
5 回答
1863 浏览
提问于 2025-04-15 13:26

基本上,我想使用所有标准的 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__ 

撰写回答