在搜索这个主题时,我遇到了以下问题:How to represent integer infinity?
我同意Martijn Peeters的观点,即为int
添加一个单独的特殊无穷大值可能不是最好的主意。在
然而,这使得类型暗示变得困难。假设以下代码:
myvar = 10 # type: int
myvar = math.inf # <-- raises a typing error because math.inf is a float
但是,代码在任何地方都会按照它应该的方式运行。我的类型暗示在其他地方都是正确的。在
如果我改写以下内容:
^{pr2}$我可以毫不费力地分配math.inf
。但现在任何其他的浮动也被接受了。在
有没有一种方法可以正确地约束类型提示?或者我每次分配无穷大时都被迫使用type: ignore
?在
超级懒惰(可能是不正确的)解决方案:
与添加特定值不同,} 包装所需的值将能够更好地向类型暗示系统指明特定的值(即
int
类可以通过子类化进行扩展。这种方法并不是没有很多陷阱和挑战,例如需要处理各种__dunder__
方法的无穷大值(即__add__
、__mul__
、__eq__
等,所有这些都应该进行测试)。在需要特定值的用例中,这将是不可接受的开销。在这种情况下,用^{inf = cast(int, math.inf)
)可以被分配。在这种方法不正确的原因很简单:因为分配的值看起来/感觉像某个数字,所以API的其他一些用户可能会无意中将其用作
int
,然后当提供math.inf
(或类似的变体)时,程序可能会在这些值上严重爆炸。在一个类比是这样的:假设列表中的项是用正整数索引的,我们希望任何返回某个项索引的函数都是正整数,所以我们可以直接使用它(我知道在Python中不是这样,因为有允许使用负索引值的语义,但是假设我们正在使用暂时说C)。假设这个函数返回匹配项的第一个匹配项,但是如果有任何错误,它将返回一些负数,这显然超出了某个项的索引的有效值范围。对于返回值的幼稚使用缺乏防范,这将不可避免地导致类型系统应该解决的问题。在
本质上,创建代理项值并将其标记为
int
将提供零值,并且不可避免地允许程序显示由于错误使用而导致的意外和损坏的API/行为。在更不用说infinity is not a number,因此没有一个
int
值可以恰当地表示这一点(假设int
表示某个有限数的性质)。在另外,看看^{} vs^{} 。其中一个返回值肯定违反了用户的期望值(即超出了正整数类型的边界;不会被告知返回值对于可能在编译时使用的上下文无效,从而导致在运行时随机出现故障)。在
用更正确的措辞来确定问题/答案:
给定的问题实际上是在一个速率存在时分配一些整数,如果不存在,则应该做一些表示特定用例的无界的其他标记(它可以是一些内置值,例如})。然而,由于这些标记也不是
NotImplemented
或{int
值,这意味着myvar
实际上需要一个包含这些值的类型,并提供一种应用操作的方法来执行正确的操作。在不幸的是,这在Python中不是以一种非常好的方式直接可用的,但是在像Haskell这样的强静态类型语言中,更被接受的解决方案是使用^{} 类型来定义number type that can accept infinity。请注意,虽然浮点无穷大也可用,但它继承了浮点数的所有问题,这些问题使得解决方案不可行(同样,不要为此使用
inf
)。在回到Python:根据您实际想要的赋值的属性,它可以很简单地创建一个类,该构造函数可以接受}(或
int
或{NotImplemented
),然后提供一个方法,该类的用户可以使用实际值。不幸的是,Python没有提供高级的构造来使它变得优雅,因此您将不可避免地以管理代码而告终,这些代码被分散在所有地方,或者必须编写一些方法来按预期处理任何输入,并以程序的特定方式生成所需的输出实际需要。在不幸的是,类型暗示实际上只不过是皮毛而已,只是简单地忽略了更高级的语言在更基本的层面上提供和解决的问题。我想如果一个人必须用Python编程,那总比没有它好。在
相关问题 更多 >
编程相关推荐