3

我有点卡在这里。我基本上处于试验阶段,我想知道我是否可以进行子类化int,以便它完全像你的好 old 一样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)是我希望能够安全地公开单独的计数(以便有人可以推送类似的日志:“加载(1500 = 10 * 10 * 未知 * 15)元素”并且仍然通过关于其中一些是“未知”的信息。

背景等级 2

我实际上很喜欢当库提供此类用于定义可迭代对象'时的情况__len__,以便它们可以返回基于“最小值”、“最大值”或“最佳猜测”的数字,而仍然不是被它在一些简单的数学中的进一步使用所困扰。

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

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

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

4

3 回答 3

3

我认为有一些概念问题胜过您的实施问题。

将“未知值”视为 1 使它们不是真正未知的。为了类比浮点数,有一个定义明确的“非数字”将参与数学运算,但在大多数情况下会产生 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

但是你不能在不破坏数学的情况下做到这一点。

于 2013-09-23T19:10:27.350 回答
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使用您要使用的值执行超类的实例化。

于 2013-09-23T19:05:14.877 回答
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]
于 2013-09-23T19:50:43.317 回答