Python PEP 484:类型提示的独占类型

Python PEP 484:类型提示的独占类型,python,python-3.5,type-hinting,Python,Python 3.5,Type Hinting,我可以指定独占类型吗?大概是这样的: def foo(bar: Not[str]) -> None: assert not isinstance(bar, str) print(type(bar)) PEP 484不包括指定“黑名单”类型的内置方式 做那种事情通常是没有意义的——我能想到你为什么想做这样的事情的唯一原因是如果你想以某种方式区分str和Iterable[str]或Sequence[str]。如果是这样的话,不幸的是,PEP 484--str,不管是好是坏,都

我可以指定独占类型吗?大概是这样的:

def foo(bar: Not[str]) -> None:
    assert not isinstance(bar, str)
    print(type(bar))

PEP 484不包括指定“黑名单”类型的内置方式

做那种事情通常是没有意义的——我能想到你为什么想做这样的事情的唯一原因是如果你想以某种方式区分
str
Iterable[str]
Sequence[str]
。如果是这样的话,不幸的是,PEP 484--str,不管是好是坏,都是这两种类型的合法子类

在这种情况下,您最好修改您的类型签名,以区分
str
List[str]
这两个合法可区分的类。不理想,但总比没有好


也就是说,如果你真的想做这样的事情,假设你正在使用mypy,并且不介意使用肮脏的黑客,那么这是有可能的

一个技巧是基本上修改
foo
函数,使其总是返回一些东西,并滥用
重载
和非严格可选模式的语义,如下所示:

from typing import overload, Optional

@overload
def foo(bar: str) -> None: ...

# Alternatively, replace "object" below
# with the types you *do* want to allow

@overload
def foo(bar: object) -> int: ...

def foo(bar: object) -> Optional[int]:
    assert not isinstance(bar, str)
    print(type(bar))
    return 0

def main() -> None:
    x = 0

    x = foo(3)       # typechecks
    x = foo("foo")   # fails
如果您尝试在mypy中运行此命令而不使用
--strict optional
标记,mypy将用
标记最后一行,“foo”不返回值
错误。然后您需要记住,发生此错误消息是因为您传入了一个字符串参数。您还需要记住始终将
foo
函数的输出指定给一个值

(如果启用了strict optional,mypy会抱怨两个重载具有不兼容的签名。)

我们在这里主要做的是:

  • 利用以下事实,
    None
    是每种类型的合法值(因此重载是合法的)
  • 利用mypy将(作为额外的特权)警告您从一个不返回任何内容的函数中赋值的情况
  • 这是一个非常老套的主意,很可能是个坏主意。我也没有承诺这种互动将在未来继续发挥作用


    你可以尝试的第二个技巧是编写一个mypy插件来捕获你的特定案例的实例。在撰写本文时,mypy插件系统是一个没有文档记录的、暂时的、很容易更改的特性,但是如果您真的想这样做,这可能是需要调查的


    如果您特别想要区分
    str
    Sequence[str]
    Iterable[str]
    (或类似的东西),您可以尝试的其他方法是:

  • 创建自定义的打字叉和/或打字模块
  • 修改
    str
    的类定义/存根,使其不会继承
    Sequence[str]
    Iterable[str]
    (或添加幻影类型或其他内容)
  • 使用
    --custom typeshed dir
    --custom typing
    命令行参数使mypy使用自定义类型定义
  • 基本上,如果默认类型层次结构不是您想要的,请创建一个自定义层次结构



    当然,如果您使用的是其他与PEP 484兼容的检查器(例如Pycharm的内置检查器),您可能会运气不佳。

    PEP 484没有内置指定“黑名单”类型的方法

    做那种事情通常是没有意义的——我能想到你为什么想做这样的事情的唯一原因是如果你想以某种方式区分
    str
    Iterable[str]
    Sequence[str]
    。如果是这样的话,不幸的是,PEP 484--str,不管是好是坏,都是这两种类型的合法子类

    在这种情况下,您最好修改您的类型签名,以区分
    str
    List[str]
    这两个合法可区分的类。不理想,但总比没有好


    也就是说,如果你真的想做这样的事情,假设你正在使用mypy,并且不介意使用肮脏的黑客,那么这是有可能的

    一个技巧是基本上修改
    foo
    函数,使其总是返回一些东西,并滥用
    重载
    和非严格可选模式的语义,如下所示:

    from typing import overload, Optional
    
    @overload
    def foo(bar: str) -> None: ...
    
    # Alternatively, replace "object" below
    # with the types you *do* want to allow
    
    @overload
    def foo(bar: object) -> int: ...
    
    def foo(bar: object) -> Optional[int]:
        assert not isinstance(bar, str)
        print(type(bar))
        return 0
    
    def main() -> None:
        x = 0
    
        x = foo(3)       # typechecks
        x = foo("foo")   # fails
    
    如果您尝试在mypy中运行此命令而不使用
    --strict optional
    标记,mypy将用
    标记最后一行,“foo”不返回值
    错误。然后您需要记住,发生此错误消息是因为您传入了一个字符串参数。您还需要记住始终将
    foo
    函数的输出指定给一个值

    (如果启用了strict optional,mypy会抱怨两个重载具有不兼容的签名。)

    我们在这里主要做的是:

  • 利用以下事实,
    None
    是每种类型的合法值(因此重载是合法的)
  • 利用mypy将(作为额外的特权)警告您从一个不返回任何内容的函数中赋值的情况
  • 这是一个非常老套的主意,很可能是个坏主意。我也没有承诺这种互动将在未来继续发挥作用


    你可以尝试的第二个技巧是编写一个mypy插件来捕获你的特定案例的实例。在撰写本文时,mypy插件系统是一个没有文档记录的、暂时的、很容易更改的特性,但是如果您真的想这样做,这可能是需要调查的


    如果您特别想要区分
    str
    Sequence[str]
    Iterable[str]
    (或类似的东西),您可以尝试的其他方法是:

  • 创建自定义的打字叉和/或打字模块
  • 修改
    str
    的类定义/存根,使其不继承任何一个