问题描述
搜索此主题时,我遇到了以下问题:如何表示整数无穷大?
Searching for this topic I came across the following: How to represent integer infinity?
我同意 Martijn Peeters 的观点,即为 int
添加一个单独的特殊无穷大值可能不是最好的主意.
I agree with Martijn Peeters that adding a separate special infinity value for int
may not be the best of ideas.
然而,这使得类型提示变得困难.假设以下代码:
However, this makes type hinting difficult. Assume the following code:
myvar = 10 # type: int
myvar = math.inf # <-- raises a typing error because math.inf is a float
但是,代码在任何地方都按其应有的方式运行.我的类型提示在其他地方都是正确的.
However, the code behaves everywhere just the way as it should. And my type hinting is correct everywhere else.
如果我改写以下内容:
myvar = 10 # type: Union[int, float]
我可以毫不费力地分配math.inf
.但现在也接受任何其他浮动.
I can assign math.inf
without a hitch. But now any other float is accepted as well.
有没有办法正确限制类型提示?还是我每次分配无穷大时都被迫使用 type: ignore
?
Is there a way to properly constrain the type-hint? Or am I forced to use type: ignore
each time I assign infinity?
推荐答案
超级懒惰(可能不正确)的解决方案:
int
类可以通过子类化进行扩展,而不是添加特定值.这种方法并非没有许多陷阱和挑战,例如需要处理各种 __dunder__
方法(即 __add__
、__mul__
code>、__eq__
等,所有这些都应该被测试).在需要特定值的用例中,这将是不可接受的开销量.在这种情况下,使用 typing.cast 包装所需的值
将能够更好地向类型提示系统指示可以接受赋值的特定值(即 inf = cast(int, math.inf)
).
The super lazy (and probably incorrect) solution:
Rather than adding a specific value, the int
class can be extended via subclassing. This approach is not without a number of pitfalls and challenges, such as the requirement to handle the infinity value for the various __dunder__
methods (i.e. __add__
, __mul__
, __eq__
and the like, and all of these should be tested). This would be an unacceptable amount of overhead in the use cases where a specific value is required. In such a case, wrapping the desired value with typing.cast
would be able to better indicate to the type hinting system the specific value (i.e. inf = cast(int, math.inf)
) be acceptable for assignment.
这种方法不正确的原因很简单:由于分配的值看起来/感觉与某个数字完全一样,您的 API 的其他一些用户可能最终会无意中将其用作 int
,然后当提供 math.inf
(或此类的变体)时,程序可能会在它们上严重爆炸.
The reason why this approach is incorrect is simply this: since the value assigned looks/feels exactly like some number, some other users of your API may end up inadvertently use this as an int
and then the program may explode on them badly when math.inf
(or variations of such) be provided.
一个类比是这样的:鉴于列表具有由正整数索引的项目,我们希望任何返回某个项目的索引的函数都是某个正整数,因此我们可以直接使用它(我知道这不是在 Python 中的情况下,存在允许使用负索引值的语义,但假设我们目前正在使用 C).假设这个函数返回匹配项的第一次出现,但如果有任何错误,它返回一些负数,这显然超出了某个项的索引的有效值范围.这种对返回值的幼稚使用缺乏防范将不可避免地导致类型系统应该解决的问题.
An analogy is this: given that lists have items that are indexed by positive integers, we would expect that any function that return an index to some item be some positive integer so we may use it directly (I know this is not the case in Python given there are semantics that allow negative index values be used, but pretend we are working with say C for the moment). Say this function return the first occurrence of the matched item, but if there are any errors it return some negative number, which clearly exceed the range of valid values for an index to some item. This lack of guarding against naive usage of the returned value will inevitably result in problems that a type system is supposed to solve.
本质上,创建代理值并将其标记为 int
将提供零值,并且不可避免地允许程序由于错误使用而表现出意外和损坏的 API/行为.
In essence, creating surrogate values and marking that as an int
will offer zero value, and inevitably allow unexpected and broken API/behavior to be exhibited by the program due to incorrect usage be automatically allowed.
更不用说无穷大不是数字,因此没有int
值可以正确表示(鉴于 int 就其本质而言表示某个有限数).
Not to mention the fact that infinity is not a number, thus no int
value can properly represent that (given that int
represent some finite number by its very nature).
顺便说一句,请查看str.index
vs str.find代码>
.其中之一具有绝对违反用户期望的返回值(即超出正整数类型的边界;不会被告知返回值可能对编译时可能使用的上下文无效,导致运行时随机出现潜在故障).
As an aside, check out str.index
vs str.find
. One of these have a return value that definitely violate user expectations (i.e. exceed the boundaries of the type positive integer; won't be told that the return value may be invalid for the context which it may be used at during compile time, results in potential failure randomly at runtime).
鉴于问题实际上是关于在速率存在时分配一些整数,如果不存在,则应该完成一些其他表示特定用例无界的标记(它可能是一些内置值,例如 NotImplemented
或 None
).然而,由于这些标记也不是 int
值,这意味着 myvar
实际上需要一个包含这些标记的类型,并且有一种应用操作的方法可以做正确的事情.
Given the problem is really about the assignment of some integer when a rate exist, and if none exist some other token that represent unboundedness for the particular use case should be done (it could be some built-in value such as NotImplemented
or None
). However as those tokens would also not be int
values, it means myvar
would actually need a type that encompasses those, and with a way to apply operation that would do the right thing.
不幸的是,这不能以一种很好的方式直接在 Python 中使用,但是在像 Haskell 这样的强静态类型语言中,更被接受的解决方案是使用 Maybe
类型来定义 可以接受无穷大的数字类型.请注意,虽然浮点无穷大在那里也可用,但它继承了浮点数的所有问题,使其成为站不住脚的解决方案(同样,不要为此使用 inf
).
This unfortunately isn't directly available in Python in a very nice way, however in strongly static typed languages like Haskell, the more accepted solution is to use a Maybe
type to define a number type that can accept infinity. Note that while floating point infinity is also available there, it inherits all the problems of floating point numbers that makes that an untenable solution (again, don't use inf
for this).
回到 Python:根据您实际想要的赋值属性,它可以像创建一个带有可以接受 int
或 None的构造函数的类一样简单code>(或
NotImplemented
),然后提供一个方法,该类的用户可以使用实际值.不幸的是,Python 没有提供高级结构来使之变得优雅,因此您将不可避免地最终导致管理它的代码散落一地,或者必须编写许多方法来按预期处理任何输入并生成所需的输出具体方式你的程序实际需要.
Back to Python: depending on the property of the assignment you actually want, it could be as simple as creating a class with a constructor that can either accept an int
or None
(or NotImplemented
), and then provide a method which the users of the class may make use of the actual value. Python unfortunately do not provide the advanced constructs to make this elegant so you will inevitably end up with code managing this be splattered all over the place, or have to write a number of methods that handle whatever input as expected and produce the required output in the specific ways your program actual needs.
不幸的是,类型提示实际上只是触及皮毛,只是简单地掠过更高级的语言提供并在更基础的层面上解决的问题.我想如果必须用 Python 编程,总比没有好.
Unfortunately, type-hinting is really only scratching the surface and simply grazing over of what more advanced languages have provided and solved at a more fundamental level. I supposed if one must program in Python, it is better than not having it.
这篇关于我应该如何键入提示一个也可以是无限的整数变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!