子类int允许“未知”值

时间:2013-09-23 18:50:32

标签: python int subclass

我有点被困在这里。我基本上是在试验阶段,我想知道我是否可以将int子类化,以便它将与您的旧int完全一样,除了您将能够分配一个“未知”值,在算术运算的情况下,将作为1。

所以我可以说:

>>> uint(5) + 5
10
>>> uint('unknown')
unknown
>>> int(uint('unknown'))
1
>>> uint('unknown') + 5
6
>>>

事实上,它与float('inf')已经有的相似,只是我只需要整数加上单个“特殊”值。

我想象的工作方式是:

class uint(int):

    def __init__(self, value):
        self.value = value
        self.unknown = self.value == "unknown"

    def __int__(self):
        return 1 if self.unknown else self.value

    def __str__(self):
        return "unknown" if self.unknown else str(self.value)

但是当我尝试将其ValueError: invalid literal for int() with base 10: 'unknown'实例化时,此示例会抛出uint('unknown')

这可能吗?我该怎么做呢?


背景等级1

如果有人问,背景是我有一个可迭代的列表,我想用itertools.product创建一个新的。但之前,我想利用__len__,以防一些迭代器实现它,以便能够猜测(最小)最终元素的数量。所以就最终数字而言,对于那些没有__len__的迭代,我假设为1.

我想用class uint(int)执行此操作的原因是我希望能够安全地公开单独的计数(以便有人可以按下以下内容:“loading(1500 = 10 * 10 * unknown) * 15)元素“仍然传递其中一些”未知“的信息。

背景等级2

我实际上是想象一种情况,当一个库提供这个类用于定义可迭代对象'__len__时,它们可以返回一个基于“最小”,“最大”的数字或“最好的猜测”,但仍然没有被它在一些简单的数学中的进一步使用所困扰。

>>> count = uint(100, 'minimum')
>>> print count
"minimum of 100"
>>> count * 20
2000
>>>

想象一个带有迭代器的对象,它读取一个巨大的文件:为什么对象不能说“好,文件是400 MiB,所以至少有4,000条记录”?

所以一个额外的问题:什么更简单:继承int或创建一个新类,但必须实现和维护aritmethic操作的接口?

3 个答案:

答案 0 :(得分:3)

我认为存在一些概念问题会超过您的实施问题。

将“未知值”视为1使得它们并非真正未知。为了对浮点数进行类比,有一个定义良好的"Not a Number",它将参与数学运算,但在大多数情况下会产生NaN。例如:

>>> f = float('NaN')
>>> 42 * f
nan

这是一件好事,因为NaN确实不是一个数字所以使用它的算术不应该产生看似有效的结果。如果您按照建议实现了“未知整数”,则未知值将产生无意义的结果。例如:

>>> u = uint('unknown')
>>> 42 * u
42

你得到一个正确的整数,但这真的是你想要的语义吗?另一个类似的情况是除以零,这是数学上未定义的。任何可能被克隆到位的价值都会产生数学上的荒谬。由于(x/y) * y == x(当且仅当y != 0)您可能期望:

>>> (42 / 0) * 0   # this doesn't really work
42

但如果不打破数学,你就无法做到这一点。

答案 1 :(得分:2)

不完全确定您为什么要这样做,但以下情况应该有效:

class uint(int):
    def __new__(cls, value):
        unknown = value == 'unknown'
        obj = super(uint, cls).__new__(cls, 1 if unknown else value)
        obj.unknown = unknown
        return obj

    def __str__(self):
        return 'unknown' if self.unknown else super(uint, self).__str__()

这里的想法是,不是将int值存储在名为self.value的属性中,而是使用您要使用的值来执行超类的实例化。

答案 2 :(得分:2)

您可以使用None作为尚未分配的值的占位符。例如:

>>> a = [4, 3, 1, 5, 2, None, None]
>>> len(a)
7
>> a*3
[4, 3, 1, 5, 2, None, None, 4, 3, 1, 5, 2, None, None, 4, 3, 1, 5, 2, None, None]