python - 在动态属性设置上绕过 mypy 的 "Module has no attribute"

标签 python python-3.x python-3.6 mypy python-typing

我在 a.py 上有以下代码:

class Tags(enum.Flag):
    NONE = 0

    A = enum.auto()
    B = enum.auto()
    C = enum.auto()

# Allow using tags.A instead of tags.Tags.A
globals().update(Tags.__members__)

但是当我在其他文件上使用它时,mypy(理所当然地)无法识别属性:
import tags
print(tags.A)  # Module has no attribute "A"

在 Python 3.6 中有没有可能绕过这个的方法?

已知的解决方案(对我来说还不够好):
  • 使用 # type: ignore每次使用 tags.A
  • 使用 tags.Tags.A
  • 使用 __getitem__在模块级别(仅适用于 Python 3.7)
  • 最佳答案

    就个人而言,我会做的是修改我的进口做:

    from tags import Tags
    

    ..这会让我通过做 Tags.A 来引用枚举项无处不在,大惊小怪。

    但是如果你真的想继续从模块命名空间中引用这些项目,一种方法是定义一个 __getattr__ functiontags.py :

    class Tags(enum.Flag):
        NONE = 0
    
        A = enum.auto()
        B = enum.auto()
        C = enum.auto()
    
    def __getattr__(name: str) -> Tags:
        return Tags[name]
    

    在运行时,如果您尝试访问某些未在 tags 中直接定义的属性,Python 将尝试调用此函数。模块对象。 Mypy 理解这个约定并假设如果 __getattr__被定义,模块是“不完整的”。因此,它将使用返回类型作为您尝试访问的任何缺失属性的类型。

    你可能还想做 globals().update(Tags.__members__)主要是作为性能优化,跳过必须实际调用 __getattr__运行时的功能。

    这个策略只有在 tags.py 只包含一个枚举时才真正有效——否则,你需要使返回类型类似于 Union[Tags, MyOtherEnum] (这很笨拙)甚至只是 Any (这失去了使用类型检查器的好处)。

    这种策略也意味着 mypy 将无法通过考虑实际枚举值来进行更复杂的类型推断和缩小。不过,这主要仅在您使用文字枚举时才相关。

    如果有这些问题,您可能不得不采用更暴力的方法,如下所示:

    from typing import TYPE_CHECKING
    
    class Tags(enum.Flag):
        NONE = 0
    
        A = enum.auto()
        B = enum.auto()
        C = enum.auto()
    
    globals().update(Tags.__members__)
    
    if TYPE_CHECKING:
        NONE = Tags.NONE
        A = Tags.A
        B = Tags.B
        C = Tags.C
    
    TYPE_CHECKING常量在运行时总是假的,但被类型检查器认为总是真。

    但是,如果您打算不惜代价直接将这些变体告诉 mypy,您不妨跳过尝试自动更新全局变量的步骤,而是这样做:

    class Tags(enum.Flag):
        NONE = 0
    
        A = enum.auto()
        B = enum.auto()
        C = enum.auto()
    
    NONE = Tags.NONE
    A = Tags.A
    B = Tags.B
    C = Tags.C
    

    显然,像这样重复自己两次是非常不理想的,但我认为没有简单的方法可以解决它。您也许可以通过创建一个自动生成的脚本来缓解这种情况 tags.py对你来说,但这也是相当不理想的,只是出于不同的原因。

    关于python - 在动态属性设置上绕过 mypy 的 "Module has no attribute",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60739889/

    相关文章:

    python 从 if 语句和 try-except 调用自定义异常

    python-3.x - 绘制具有不等长 x 轴和 y 轴的曲面图

    python-3.x - 如何摆脱 Python Pandas 中的斜体并获取纯文本?

    python - 如何使用python限制同一字母的最长序列

    python - 为什么使用 python F 字符串插值用引号引起来?

    matplotlib - 是否可以使用seaborn绘制超过6列的线图?

    python - 从具有级别的列表构建树

    python - 尝试检查整数列表中每个元素的条件

    python - 使用 numpy 实现最大/平均池化(带步幅)

    python - 寻找随机矩阵中最可能的区域