【问题标题】:subclassing int to attain a Hex representation子类化 int 以获得十六进制表示
【发布时间】:2010-11-17 13:46:52
【问题描述】:

基本上我想访问所有标准的python int 运算符,例如__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

有什么想法吗?

【问题讨论】:

  • 为什么不直接使用内置函数hex()docs.python.org/library/functions.html#hex
  • 在众多不同的适当位置插入 hex() 将既耗时又不精确。切换任何 Hex(int) 类型的表示将是一个简单的重构。但是:我认为需要重载所有 Hex/int 二元运算符以返回 Hex 结果(目前它们仍然产生 int)。也许有一个“混合”用于批量重载运算符。

标签: python hex subclassing representation


【解决方案1】:

你应该分别定义__repr____str__

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

__repr__ 函数应该(如果可能)提供 Python 文本,该文本可以是 eval()uated 以重建原始对象。另一方面,__str__ 可以只返回对象的人类可读表示。

【讨论】:

  • 为注意到 strrepr 之间的区别而欢呼。
  • 由于 repr(23) 和 str(23) 给出完全相同的结果字符串,所以我不会因为 int 的子类也这样做而变得特别热和烦恼——毕竟如果 Hex 在一个你永远不知道是返回 'Hex(0x0)' 还是 'themodule.Hex(0x0)' 的模块(因为你不知道导入是如何表达的!)所以字符串的eval-ability 非常不确定无论如何(__import__('themodule').Hex(0x0) 可以更广泛地评估,对于不在子包中的模块,但如果我在代码审查中看到从__repr__ 返回的 THAT,我会否决提交变更集!-)。
  • 我认为__repr__ 确实是一种尽力而为的事情。显然它不能在所有情况下都做正确的事情。
  • “最好”的努力(为了最有可能 eval'able)将是上面带有__import__ 的字符串,我只是不想看到——所以“不是最好的” “ 更好。而且由于容器的__str__ 在项目上使用__repr__,我倾向于不强调这种区别。
【解决方案2】:

类装饰器,尤其是在 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)

不那么优雅,但同样有效;-)

编辑:修复了代码中出现的“常见范围问题”。

【讨论】:

  • +1。我知道必须有一个更简单的解决方案。但我不知道可以在类上使用装饰器。谢谢。
  • @Ralph,不客气!装饰器语法自 python 2.6 起才受支持,但我还展示了如何在较旧的 python 中的类上使用装饰器(语法不太优雅)(例如,2.5,例如,你被困在谷歌应用引擎中,或者作为系统提供的带有 MacOSX 和许多 Linux 发行版等的 Python;-)。
  • 这有问题(至少在 Python 2.5 上),其中 specials 中的最后一个方法名称也用于所有前面的方法,例如print a, b, a&b, a|b, a^b >>> 0x929 0x1538 0x1c11 0x1c11 0x1c11,但应该是0x929 0x1538 0x128 0x1d39 0x1c11
  • 是的,问题在于 lambda 在执行时使用方法的最后一个绑定值,所以它总是使用specials 列表中的最后一个方法。
  • 为什么是__str__ = __repr__?我猜int__str__ 不会按照object 隐含地落入__repr__。这有什么原因吗?
【解决方案3】:

回应您的评论:

你可以自己写一个 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__ 

【讨论】:

  • 为什么按照@Greg Hewgill 的回答,mixin 解决方案优于简单的子类化?
【解决方案4】:

您需要让运算符(+、-、** 等)返回 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的实例???

【讨论】:

    【解决方案5】:

    也覆盖__str__

    __repr__ 在调用 repr(o) 时使用,并在交互式提示符处显示一个值。 __str__ 在大多数字符串化对象的实例中都会调用,包括在打印对象时。

    对象的默认__str__ 行为是回退到repr,但int 提供了自己的__str__ 方法(与__repr__ 相同(在Python 3 之前),但没有退回__repr__)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 2016-02-06
      • 2014-12-20
      • 2018-02-26
      • 2013-08-20
      • 1970-01-01
      • 2021-07-12
      相关资源
      最近更新 更多