首页 > 编程问答 >Python 3.9.1 中的 collections.abc.Callable 是否有 bug?

Python 3.9.1 中的 collections.abc.Callable 是否有 bug?

时间:2024-07-28 05:08:35浏览次数:9  
标签:python python-typing python-3.9 python-collections

Python 3.9 包含 PEP 585 并弃用 typing 模块中的许多类型,转而支持 collections.abc 中的类型,现在它们支持 __class_getitem__ 例如 Callable 就是这种情况。对我来说, typing.Callable collections.abc.Callable 的行为应该总是相似的,但事实并非如此。

这个简单的示例会导致错误:

>>> from typing import Optional
>>> from collections.abc import Callable
>>> def foo(arg: Optional[Callable[[int], int]]) -> None:
...    pass
...
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/lib/python3.9/typing.py", line 262, in inner
    return func(*args, **kwds)
  File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
    return self._getitem(self, parameters)
  File "/usr/local/lib/python3.9/typing.py", line 463, in Optional
    return Union[arg, type(None)]
  File "/usr/local/lib/python3.9/typing.py", line 262, in inner
    return func(*args, **kwds)
  File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
    return self._getitem(self, parameters)
  File "/usr/local/lib/python3.9/typing.py", line 451, in Union
    parameters = _remove_dups_flatten(parameters)
  File "/usr/local/lib/python3.9/typing.py", line 231, in _remove_dups_flatten
    return tuple(_deduplicate(params))
  File "/usr/local/lib/python3.9/typing.py", line 205, in _deduplicate
    all_params = set(params)
TypeError: unhashable type: 'list'

但同样的错误不会发生在 typing.Callable :| 中。 ||如果签名稍微简化一点,也不会发生该错误:

>>> from typing import Callable
>>> def foo(arg: Optional[Callable[[int], int]]) -> None:
...    pass
...
>>> # no error

这是 Python 3.9 和 3.9.1 中的错误吗?

>>> from collections.abc import Callable
>>> def foo(arg: Optional[Callable[..., int]]) -> None:
...    pass
...
>>> # no error
>>> def foo(arg: Callable[[int], int]) -> None:
...    pass
...
>>> # no error

Is this a bug in Python 3.9 and 3.9.1?


这不是 Python 中的错误,而是使用 collections.abc.Callable 时的一个微妙问题,与 typing.Callable 相比。虽然 PEP 585 旨在使内置类型与来自 typing 的类型可互换用于类型提示,但在这种情况下,交互的复杂性会导致行为上的差异。

以下是发生错误的原因:

  1. typing.Callable 是一个特殊的类型提示。 它被 Python 类型检查器特殊处理,并理解如何以类型提示的方式处理其参数。

  2. collections.abc.Callable 是一个抽象基类。 它旨在用于运行时检查对象是否可调用,但它没有 typing.Callable 的特殊类型提示行为。

  3. 当执行 Optional[Callable[[int], int]] 时,会发生类型嵌套。 Optional[x] 只是 Union[x, None] 的简写。 问题出在 Union 试图“规范化”其参数,这涉及到迭代和散列它们。

  4. 不能对 list 进行散列。 Union 试图规范化具有 collections.abc.Callable[[int], int] 的类型时,它将 [int] 视为一个列表(因为它实际上是一个列表),并尝试对其进行散列,从而导致 TypeError

解决方案:

  • 坚持使用 typing.Callable 进行类型提示。 这是解决此类问题的推荐方法。 typing.Callable 旨在用于类型提示,并且由类型检查器专门处理。

  • 如果出于某种原因需要使用 collections.abc.Callable ,请避免在需要对其进行散列的上下文中使用它(例如,在 Union 中)。

请记住,即使在 Python 3.9+ 中, typing 模块对于类型提示仍然很重要,而且在许多情况下,其行为与 collections.abc 中的对应物不完全相同。

标签:python,python-typing,python-3.9,python-collections
From: 65858528

相关文章

  • 列表子类的 Python 类型
    我希望能够定义列表子类的内容必须是什么。该类如下所示。classA(list):def__init__(self):list.__init__(self)我想包含键入内容,以便发生以下情况。importtypingclassA(list:typing.List[str]):#Maybesomethinglikethisdef__init__(self):......
  • Python 中类型友好的委托
    考虑以下代码示例defsum(a:int,b:int):returna+bdefwrap(*args,**kwargs):#delegatetosumreturnsum(*args,**kwargs)该代码运行良好,只是类型提示丢失了。在Python中使用*args,**kwargs来实现​​委托模式是很常见的。如果有一种方法可......
  • 使用 python 支持构建自定义 vim 二进制文件
    背景Debian11vim软件包不包含python3支持。请参阅标题为“Debian11vim中不支持python-证据”的部分下面我需要vim支持python3YouCompleteMevim插件为了构建一个新的,我将vim9.0tarball下载到v......
  • 如何在Python 3.12+中正确使用泛型来提高代码质量?
    我正在尝试使用泛型来改进FastAPI应用程序中的类型注释。我有一个抽象存储库类,在其中使用泛型:fromabcimportABC,abstractmethodfromtypingimportListclassAbstractRepository[T](ABC):@abstractmethodasyncdefadd_one(self,data:dict)->T:......
  • python中的while循环不退出
    我试图完成第一年的python商业课程作业,但我的while循环无法退出,有人能帮忙吗?commisionTable=[{"admin_fee":100,"comm_rate":0.10},{"admin_fee":125,"comm_rate":0.12},{"admin_fee":150,"comm_rate":......
  • python---json文件写入
    ​ 使用到的知识点:os模块执行linux指令、json.dump()、withopenasf代码实现importsysimportosimportjson #向json文件file中添加内容data,其中data的类型为字典defwrite_json(file,data):    #如果文件存在,则删除    if(os.path.exists(fi......
  • python错题记录:布尔运算与逻辑值检测
    一前言环境:python3.10win10二布尔运算与逻辑值检测1案例案例1如上,在布尔运算时,有些时候代码只会运算前面的一部分,剩下的部分根本不会运算。以前在练习算法代码时,就利用这个规则来减少代码的工作量案例2如上,之前好长一段时间,上面的布尔运算总是让我感到困惑布尔运......
  • python---字典遍历
    1、三种常见的字典遍历实现defget_key_value(dics):  '''遍历所有键值对'''  forkey,valueindics.items():    print(f"{key}:{value}")defget_keys(dics):  '''遍历所有的键'''  forkeyindics......
  • python基本语法三天速成系列day1(看完这篇你就会)
    注释注释是代码非常重要的一部分,它的主要作用有:解释代码目的:注释可以说明代码段或函数的目的和功能,帮助其他开发者快速理解代码的意图。复杂逻辑说明:对于复杂的算法或业务逻辑,通过注释可以解释这些逻辑是如何工作的,降低后续维护的难度。提高可读性:良好的注释可以使代码结......
  • Python学习笔记46:游戏篇之外星人入侵(七)
    前言到目前为止,我们已经完成了游戏窗口的创建,飞船的加载,飞船的移动,发射子弹等功能。很高兴的说一声,基础的游戏功能已经完成一半了,再过几天我们就可以尝试驾驶飞船击毁外星人了。当然,计分,游戏次数,背景音乐,开始启动等按钮的功能需要我们慢慢添加,这些功能不影响游戏的使用,影......