【问题标题】:python typing + Literal with parameterspython输入+带参数的文字
【发布时间】:2021-11-14 21:48:00
【问题描述】:

我正在尝试使用Literal 在 python 中构建用户定义的类型。这个想法是准确描述给定函数的可接受参数。想象一下我使用 2bits str 并返回一个 int

def foo(x: str)->int:
   assert len(x)==2
   assert all(map(lambda x:x in ['0', '1'], x))
   return 0

将是一种强制执行此操作的方法。但我希望我的类型检查器静态地完成这项工作,所以我可以做类似的事情:

from typing import Literal

ValidEntry = Literal["00", "01", "10", "11"]


def foo(x: ValidEntry)->int:
   return 0

foo("01")
foo("bar")
foo(01)

针对前面的代码调用mypy 将在最后两次调用foo 时引发错误,如预期的那样。

我现在的问题是:如果我想定义 Byte 类型,我该怎么做。我试图将所有可能的 8 位字的列表传递给使用 itertools.product 计算的 Literal

from itertools import product
from functools import reduce
from typing import Literal, List


def comb(n):
    tuple2str = lambda t: reduce(lambda x, y: x + y, t, "")
    return [tuple2str(t) for t in product("01", repeat=n)]


Bytes = List[Literal[c] for c in comb(8)]

mypy 拒绝这个。 pyright 错误并显示以下消息:"c" is not defined"Literal['00001001']" is incompatible with "Bytes"

无法从 PEP586 中找到解决方案。欢迎任何提示!也许Literal 不是正确的做法......

【问题讨论】:

  • 顺便说一句,您知道静态类型检查器实际上不能运行时用户输入检查...?
  • 这不是需要大量内存而没有太多好处吗?考虑想要 32 位整数……有很多字符串要为它们创建。
  • 我不是在寻找任何围绕 nbits 整数的真实世界用例。以它为例。我感兴趣的是了解Literal 的工作原理。我可以用它来构建一个用户定义的类型,其中包含意图给出的对象列表吗?这是我感兴趣的问题。
  • @deceze 是的,我愿意。

标签: python type-hinting python-typing


【解决方案1】:

这可能不实用,但只是出于教育目的,我们可以看看Literal 是如何实现的:

@_LiteralSpecialForm
def Literal(self, parameters):
  ...
  return _LiteralGenericAlias(self, parameters)

所以我们可以使用:

import typing
from functools import reduce
from typing import _LiteralGenericAlias

from itertools import product


def comb(n):
    tuple2str = lambda t: reduce(lambda x, y: x + y, t, "")
    return [tuple2str(t) for t in product("01", repeat=n)]


Bytes = _LiteralGenericAlias(typing.Literal, [c for c in comb(8)])

这会产生以下文字:

>>> print(Bytes)
typing.Literal[['00000000', '00000001', '00000010', '00000011', '00000100', '00000101', '00000110', '00000111', '00001000', '00001001', '00001010', '00001011', '00001100', '00001101', '00001110', '00001111', '00010000', '00010001', '00010010', '00010011', '00010100', '00010101', '00010110', '00010111', '00011000', '00011001', '00011010', '00011011', '00011100', '00011101', '00011110', '00011111', '00100000', '00100001', '00100010', '00100011', '00100100', '00100101', '00100110', '00100111', '00101000', '00101001', '00101010', '00101011', '00101100', '00101101', '00101110', '00101111', '00110000', '00110001', '00110010', '00110011', '00110100', '00110101', '00110110', '00110111', '00111000', '00111001', '00111010', '00111011', '00111100', '00111101', '00111110', '00111111', '01000000', '01000001', '01000010', '01000011', '01000100', '01000101', '01000110', '01000111', '01001000', '01001001', '01001010', '01001011', '01001100', '01001101', '01001110', '01001111', '01010000', '01010001', '01010010', '01010011', '01010100', '01010101', '01010110', '01010111', '01011000', '01011001', '01011010', '01011011', '01011100', '01011101', '01011110', '01011111', '01100000', '01100001', '01100010', '01100011', '01100100', '01100101', '01100110', '01100111', '01101000', '01101001', '01101010', '01101011', '01101100', '01101101', '01101110', '01101111', '01110000', '01110001', '01110010', '01110011', '01110100', '01110101', '01110110', '01110111', '01111000', '01111001', '01111010', '01111011', '01111100', '01111101', '01111110', '01111111', '10000000', '10000001', '10000010', '10000011', '10000100', '10000101', '10000110', '10000111', '10001000', '10001001', '10001010', '10001011', '10001100', '10001101', '10001110', '10001111', '10010000', '10010001', '10010010', '10010011', '10010100', '10010101', '10010110', '10010111', '10011000', '10011001', '10011010', '10011011', '10011100', '10011101', '10011110', '10011111', '10100000', '10100001', '10100010', '10100011', '10100100', '10100101', '10100110', '10100111', '10101000', '10101001', '10101010', '10101011', '10101100', '10101101', '10101110', '10101111', '10110000', '10110001', '10110010', '10110011', '10110100', '10110101', '10110110', '10110111', '10111000', '10111001', '10111010', '10111011', '10111100', '10111101', '10111110', '10111111', '11000000', '11000001', '11000010', '11000011', '11000100', '11000101', '11000110', '11000111', '11001000', '11001001', '11001010', '11001011', '11001100', '11001101', '11001110', '11001111', '11010000', '11010001', '11010010', '11010011', '11010100', '11010101', '11010110', '11010111', '11011000', '11011001', '11011010', '11011011', '11011100', '11011101', '11011110', '11011111', '11100000', '11100001', '11100010', '11100011', '11100100', '11100101', '11100110', '11100111', '11101000', '11101001', '11101010', '11101011', '11101100', '11101101', '11101110', '11101111', '11110000', '11110001', '11110010', '11110011', '11110100', '11110101', '11110110', '11110111', '11111000', '11111001', '11111010', '11111011', '11111100', '11111101', '11111110', '11111111']]

【讨论】:

  • Python 的静态类型检查器(目前)无法理解动态计算的类型提示。请参阅 mypy 文档:“文字类型不能包含任意表达式:Literal[my_string.trim()]Literal[x > 3]Literal[3j + 4] 等类型都是非法的。” 因此,我认为如果您这样做会很有用在您的回答中澄清说,如果您直接将Bytes 文字的 evaluated 形式复制并粘贴到某处的源代码中,这仅适用于静态分析。 mypy.readthedocs.io/en/stable/…
猜你喜欢
  • 1970-01-01
  • 2019-11-11
  • 2013-03-30
  • 2016-10-16
  • 2014-08-02
  • 2015-06-04
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多