2

我有一个 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)

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

4

2 回答 2

1

到目前为止,处理这个问题的最简单和最方便的方法就是不对config参数进行注释,或者将其注释为Any. 您可以提供更具体的注释,但它会变得非常尴尬。

您现有注释的问题在于您f1被注释为将任意模块作为参数,并且任意模块可能没有NAME属性。(也是ModuleTypein types,不是typing。)一个正确的、特定的注解f1将指定它接受带有NAME属性的东西,您可以使用自定义协议类指定它:

import typing

class HasName(typing.Protocol):
    NAME: str

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

但是你必须为你想要定义的所有东西做这个,config如果你想允许可选的配置定义在config.

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

f1(typing.cast(HasName, config))

这是非常尴尬的。另外,一旦你有了这个演员,mypy 即使config 没有属性也不会报告错误NAME,所以你从所有这些尴尬的工作中根本没有安全感。

于 2021-05-12T00:13:15.667 回答
-1

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

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

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

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

于 2021-05-11T23:56:46.390 回答