PEP 484: exclusive type for type hint

╄→尐↘猪︶ㄣ 提交于 2020-08-06 05:02:11

问题


Could I specify exclusive type? Something like this:

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

回答1:


PEP 484 does not include a built-in way of specifying a "blacklisted" type.

Doing that kind of thing typically doesn't really make sense -- the only reason I can think of why you might want to do something like this is if you wanted to distinguish between str and Iterable[str] or Sequence[str] in some fashion. If that's the case, PEP 484 unfortunately doesn't have a way of letting you do this -- str, for better or for worse, is a legitimate subclass of those two types.

Your best bet in this case is to modify your type signature to distinguish between str and List[str] which are legitimately distinguishable classes. Not ideal, but better then nothing.


That said, if you really do want to do something like this, it's sort of possible to do so, assuming you're using mypy and don't mind resorting to dirty hacks.

One hack is to basically modify your foo function so it always returns something and abuse overload and the semantics of non-strict optional mode, like so:

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

If you try running this in mypy WITHOUT the --strict-optional tag, mypy will flag the last line with a "foo" does not return a value error. You would then need to remember that this error message occurs because you passed in a string argument. You would also need to remember to always assign the output of your foo function to a value.

(If you do enable strict-optional, mypy will complain that your two overloads have incompatible signatures.)

What we're basically doing here is:

  1. Exploiting the fact that with strict-optional disabled, None is a legal value of every type (so the overload is legal)
  2. Exploiting the fact that mypy will (as an extra perk) warn you of cases where you assign a value from a function that doesn't return anything.

This is all pretty hacky and very likely a bad idea. I also make no promises that this interaction will continue to work in the future.


The second hack you could try is to write a mypy plugin to catch instances of your specific case. The mypy plugin system is, as of time of writing, an undocumented, tentative, and highly-prone-to-change feature, but if you really want to do this, that might be something to investigate.


If you're specifically trying to distinguish between str and Sequence[str] or Iterable[str] (or something similar), something else you can try is to:

  1. Create a custom fork of Typeshed and/or the typing module
  2. Modify the class definition/stubs for str so it doesn't inherit from either Sequence[str] or Iterable[str] (or add phantom types or something)
  3. Make mypy use your custom type definitions using the --custom-typeshed-dir and --custom-typing command line arguments.

Basically, if the default type hierarchy isn't quite what you want, invent a custom one.


Of course, if you're using some other PEP 484 compliant checker (such as Pycharm's built in checker), you're probably out of luck.



来源:https://stackoverflow.com/questions/46313872/pep-484-exclusive-type-for-type-hint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!