微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

包含常量的模块的类型提示

如何解决包含常量的模块的类型提示

我有一个 config.py 文件,其中包含一个常量列表,例如:

config.py
NAME = 'John'
AGE = 23

在另一个文件中,我将此文件作为模块导入,然后将其作为参数传递给其他函数。我使用 ModuleType 作为这个参数的类型。

import config
from types import ModuleType
def f1(config: ModuleType) -> None:
    print(config.NAME)

问题是当我运行pyright linter时,它报告了一个错误

 79:30 - error: Cannot access member "NAME" for type "ModuleType"
    Member "NAME" is unkNown (reportGeneralTypeIssues)

键入提示配置以避免这些错误的正确方法是什么?谢谢!

解决方法

到目前为止,最简单、最方便的处理方法是不注释 config 参数,或将其注释为 Any。您可以提供更具体的注释,但会变得非常尴尬。

您现有注释的问题在于您的 f1 被注释为将任意模块作为参数,并且任意模块可能没有 NAME 属性。 (还有 ModuleTypetypes 中,而不是 typing。)f1 的正确、特定注释会指定它需要带有 NAME 属性的东西,即您可以使用自定义协议类指定:

import typing

class HasName(typing.Protocol):
    NAME: str

def f1(config: HasName) -> None:
    print(config.NAME)

但是您必须为要在 config 中定义的所有内容执行此操作,如果您想在 config 中允许可选配置定义,则会变得更加尴尬。

此外,如果您现在尝试将 config 作为参数传递给 f1,它仍然将不起作用,因为当您将模块作为参数传递时, mypy 仅将其视为通用模块,不考虑其内容。 (我不知道 pyright 做什么,但这就是 mypy 处理它的方式。)您必须显式转换 config

f1(typing.cast(HasName,config))

这太尴尬了。另外,一旦你有了这个演员,即使 config 没有 有一个 NAME 属性,mypy 也不会报告错误,所以你没有获得安全完全来自这些尴尬的工作。

,

事实证明,所有模块都是 types.ModuleType 的子类型,因此是 typing.ModuleType。因此,您想要的是:

def f1(config: config) -> None:
    print(config.NAME)

第一个 config 只是一个形式参数,第二个通过名称引用模块。 typing 模块将实际导入成员,并且一切正常。

这确实让我想知道这有什么意义。如果必须导入模块才能定义函数,那为什么还要将其作为参数传递?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。