在旧版本的 Python 上使用现代打字功能

问题描述 投票:0回答:2

所以,我正在使用 Python 编写一个事件发射器类。

代码目前如下所示:

from typing import Callable, Generic, ParamSpec

P = ParamSpec('P')

class Event(Generic[P]):
  def __init__(self):
    ...

  def addHandler(self, action : Callable[P, None]):
    ...

  def removeHandler(self, action : Callable[P, None]): 
    ...

  def fire(self, *args : P.args, **kwargs : P.kwargs):
    ...

如您所见,注释依赖于

ParamSpec
,仅在Python 3.10中添加到
typing

虽然它在 Python 3.10(在我的机器上)中运行良好,但在 Python 3.9 及更早版本(在其他机器上)中却失败了,因为

ParamSpec
是一项新功能。

那么,在运行程序时如何避免导入

ParamSpec
或使用一些后备替代方案,同时不混淆在编辑器中的输入(pyright)?

python python-typing
2个回答
9
投票

我不知道是否有任何理由重新发明轮子,但是

typing_extensions
模块由python核心团队维护,支持
python3.7
及更高版本,并且正是用于此目的。您只需检查 python 版本并选择正确的导入源即可:

import sys

if sys.version_info < (3, 10):
    from typing_extensions import ParamSpec
else:
    from typing import ParamSpec

1
投票

这可以通过将

from typing import ...
包装成
if TYPE_CHECKING
来解决:

if TYPE_CHECKING:
    from typing import Callable, Generic, ParamSpec
else:
    # Fake ParamSpec
    class ParamSpec:
        def __init__(self, _):
            self.args = None
            self.kwargs = None
    # Base class to be used instead Generic
    class Empty:
        pass
    # Thing what returns Empty when called like Generic[P]
    class _Generic:
        def __getitem__(self, _):
            return Empty
    # Callable[anything] will return None
    class _Callable:
        def __getitem__(self, _):
            return None
    # Make instances
    Callable = _Callable()
    Generic = _Generic()

... code

if not TYPE_CHECKING:
    # To allow usage of
    # evt : Event[[int, str]]

    # Store existing Event class
    _Event = Event
    class FakeEvent:
        # Event(...) calls original constructor
        def __call__(self, *args, **kwds):
            return _Event(*args, **kwds)
        # Event[...] returns original Event
        def __getitem__(self, _):
            return _Event
    # Replace Event class
    Event = FakeEvent()

这允许代码在旧版本的 Python 上运行,同时在编辑器中使用 3.10 版本的输入。

© www.soinside.com 2019 - 2024. All rights reserved.