【问题标题】:Subclassing int - unexpected behaviour with range子类化 int - 范围内的意外行为
【发布时间】:2017-07-31 12:10:52
【问题描述】:

我们试图创建一个可变的 int,它从其他地方引用它的值。它似乎在大多数情况下都表现良好,但是,当将其交给范围时,我们会得到意想不到的结果。

子类包含一堆样板,所以我将包含我知道的方法,这些方法被范围调用以推断 int 的值,这将重现行为。

class IntRef(int):

    def __init__(self, *args, **kwargs):
        self.reference = 5
        super().__init__()

    def __le__(self, other):
        return self.reference.__le__(other)

    def __sub__(self, other):
        return self.reference.__sub__(other)

    ...

这种行为:

a = IntRef()
list(range(a)) # [] not [0, 1, 2, 3, 4]

我相信我们已经实现了与 int 关联的所有 Dunder 方法,因此我希望 range 创建一个零 - 4 列表。

在查找值时,range 是否会假设“值”在 int 类型类中的存储位置?在 Python 中制作透明引用类型框的最佳方法是什么?

谢谢

【问题讨论】:

  • range 应该如何知道它应该访问其参数的reference 属性?换句话说,它只是认为你通过了0:a = IntRef() ; print(a) # 0

标签: python-3.x reference int subclassing


【解决方案1】:

您在 IntRef.__new__ 中没有做任何不同的事情,因此通过调用 IntRef() 并使用 int.__new__ 您将返回 0 的值。

定义一个合适的IntRef.__new__:

class IntRef(int):

    def __new__(cls, reference=5, *args, **kwargs):
        return super().__new__(cls, reference, *args, **kwargs)

你会得到想要的结果:

a = IntRef()
list(range(a))
Out[78]: [0, 1, 2, 3, 4]

但是使用参数似乎很奇怪和令人困惑;我会坚持使用默认的 int 行为并使用 IntRef(5) 初始化 IntRef

【讨论】:

  • 我会使用默认值 0 以保持与 Python 中其他类型的兼容性。即int(), float(), list(), set()等都返回它们对应的“零值”:0, 0.0, [], {}
  • 感谢您的回复。澄清一下:我希望能够在运行时更改 IntRef.reference 对象的值——我不相信这是允许的。我写了一个 newinit 方法植入,但没想到要包含 - 我应该有。
  • @freebie 虽然我没有对此进行测试,但您可能可以通过将reference 设为属性并返回IntRef 的新实例(通过初始化新的@987654335属性实现中的@对象)当reference被访问时。
【解决方案2】:

不要继承int,然后覆盖所有方法。如果你这样做,基类会认为你有一个值,而子类会认为你有不同的值。相反,继承numbers.Integral 并实现所有抽象方法。然后你就可以确定你的实现是城里唯一的游戏。

【讨论】:

  • 太棒了。听起来像我正在寻找的那种东西。您知道子类成分积分是否会影响性能?
  • @freebie:Python 整数是用 C 语言实现的,所以我想它们会稍微快一些,但除非你有一个有代表性的用例基准测试,否则这可能不是你的那种微优化想做的事。您(大概)选择 Python 是因为它可读性强,而不是因为它速度快。
  • 非常正确。我只是好奇,因为使用纯 python UserDict 的开销(您可能只能访问几次)将非常微不足道。虽然我觉得对原始类型做同样的事情,但我认为它会以更多的方式被访问,但可能会产生更大的影响。我想我会发现的。如果一切顺利,我会试一试 Intergral 并奖励你答案。再次感谢
  • 如果我尝试将浮点数除以积分,这似乎会崩溃。我不知道我是否能够得到我所追求的
  • @freebie:这是一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 2015-08-11
  • 2017-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多