【问题标题】:Mypy is not able to find an attribute defined in the parent NamedTupleMypy 无法找到父 NamedTuple 中定义的属性
【发布时间】:2022-12-05 07:23:13
【问题描述】:

在我的项目中,我使用的是Fava。 Fava,正在使用Beancount。通过在mypy.ini 中设置mypy_path,我已经将Mypy 配置为在本地读取存根。 Mypy 能够读取配置。到目前为止,一切都很好。

考虑我的这个功能

1 def get_units(postings: list[Posting]):
2    numbers = []
3    for posting in postings:
4        numbers.append(posting.units.number)
5    return numbers

当我运行mypy src时,出现以下错误

report.py:4 error: Item "type" of "Union[Amount, Type[MISSING]]" has no attribute "number"  [union-attr]

当我检查定义的存根 here 时,我可以看到 units 的类型是 Amount。现在,Amount 正在从其父级 _Amount 继承 number。回到Fava 中的存根,我可以看到类型here

我的问题是为什么 mypy 找不到属性 number 尽管它是在存根中定义的?

【问题讨论】:

    标签: python mypy


    【解决方案1】:

    units 的类型不是 Amount

    class Posting(NamedTuple):
        account: Account
        units: Union[Amount, Type[MISSING]]
    

    这是Union[Amount, Type[MISSING]]就像错误信息所说的一样.如果它是 Type[MISSING] 则没有 number 属性,就像错误信息所说的一样.如果您要运行此代码并且 units 实际上是 MISSING,它将在尝试访问该 number 属性时引发 AttributeError

    (旁白:我不熟悉 beancount,但这对我来说似乎是一个奇怪的界面——IMO 更惯用的做法是将它设为 Optional[Amount]None 代表“缺失”的情况。 )

    您需要更改您的代码以说明 MISSING 的可能性,以便 mypy 知道您知道它(并且您的代码的读者可以在它以 @987654336 的形式咬他们之前看到这种可能性@).就像是:

    for posting in postings:
        assert isinstance(posting.units, Amount), "Units are MISSING!"
        numbers.append(posting.units.number)
    

    显然,如果你想让你的代码做一些事情而不是在MISSINGunits上引发AssertionError,你应该编写你的代码来做那件事而不是assert

    如果你只想假设它是一个Amount,如果不是,则在运行时引发一个AttributeError,使用typing.cast告诉mypy你想认为它是一个Amount,即使类型存根另有说明:

    for posting in postings:
        # posting.units might be MISSING, but let's assume it's not
        numbers.append(cast(Amount, posting.units).number)
    

    【讨论】:

      猜你喜欢
      • 2013-10-15
      • 1970-01-01
      • 2019-03-02
      • 2015-03-01
      • 2018-09-29
      • 2020-09-18
      • 2014-10-01
      • 2020-10-04
      • 2018-12-29
      相关资源
      最近更新 更多