Python 子类int允许;“未知”;价值

Python 子类int允许;“未知”;价值,python,int,subclass,Python,Int,Subclass,我被困在这里了。我基本上处于实验阶段,我想知道我是否可以将int子类化,这样它就可以完全像你以前的int一样工作,只是你可以分配一个“未知”值,在进行算术运算时,这个值将作为1 所以我可以说: >>> uint(5) + 5 10 >>> uint('unknown') unknown >>> int(uint('unknown')) 1 >>> uint('unknown') + 5 6 >>> 事实上

我被困在这里了。我基本上处于实验阶段,我想知道我是否可以将
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)
但是,当我尝试将int()实例化为
uint('unknown')
时,这个示例抛出
ValueError:invalid literal for int(),以10为基数:“unknown”

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


背景级别1

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

我想用
类uint(int)
这样做的原因是,我希望能够安全地公开单独的计数(以便有人可以在日志中插入类似“加载(1500=10*10*未知*15)元素”这样的内容),并且仍然传递其中一些元素“未知”的信息

背景级别2

实际上,我在想象这样一种情况:a库提供了这个类,用于定义iterable对象的
\uu len\uuu
,这样它们就可以返回一个基于“最小”、“最大”或“最佳猜测”的数字,而不必为它在一些简单数学中的进一步使用而烦恼

>>> count = uint(100, 'minimum')
>>> print count
"minimum of 100"
>>> count * 20
2000
>>>
想象一个对象使用一个迭代器读取一个巨大的文件:为什么该对象不能说“这个文件是400个MiB,所以至少会有4000条记录”


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

不太清楚为什么要这样做,但以下应该可以:

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
的属性中,而是使用您想要使用的值来执行超类的实例化。

我认为存在一些概念问题,而不是实现问题

将“未知值”视为1并不意味着它们真的未知。与浮点数相比,有一个定义良好的值,它将参与数学运算,但在大多数情况下会产生NaN。例如:

>>> f = float('NaN')
>>> 42 * f
nan
>>> u = uint('unknown')
>>> 42 * u
42
>>> 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]
这是一件好事,因为NaN实际上不是一个数字,所以使用它的算术不会生成看似有效的结果。如果您按照建议实现“未知整数”,未知值将产生无意义的结果。例如:

>>> f = float('NaN')
>>> 42 * f
nan
>>> u = uint('unknown')
>>> 42 * u
42
>>> 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]
你得到了一个正确的整数,但这真的是你想要的语义吗?另一个类似的情况是被数学上未定义的零除。任何可能被混淆的值都会产生数学上的荒谬。因为
(x/y)*y==x
(当且仅当
y!=0
)你可能期望:

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

但是,如果不打破数学,就不能这样做。

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

>>> f = float('NaN')
>>> 42 * f
nan
>>> u = uint('unknown')
>>> 42 * u
42
>>> 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]

为什么
1
?这背后的语义是什么?还有,这与具有
int
字段(也可以是
None
)有何不同?如果您正在寻找方法来处理一组未知观察值中的值,有许多标准方法来处理。但这与您所问的问题不同。I我已经读了你添加的“背景”三遍,它似乎并没有使你的目标更加明确。然而,“我是否应该子类int”更明显地是“否”。无论你的“未知”是什么,它都没有通过OO设计的“is-a int”测试。由于你的回答,我立即进入Python解释器并键入
x=(42/0)*0
并期望得到42个作为某种隐藏的复活节彩蛋。我非常失望:(+1无论如何,你认为它会给生命、宇宙和一切带来答案?很抱歉让你失望;)我把它弄得更清楚了,谢谢你隐含的更正。好吧,这是有效的。除了在阅读了msw的评论和回答之后,我可能在重新思考我的策略,但你的解决方案有效,并告诉我如何打破数学。接受。