Python os.getenv 的类型提示导致下游不兼容的类型错误
Python typehint for os.getenv causes downstream incompatible type errors
使用 os.getenv
检索环境变量时,默认行为 return 是 Optional[str]
的一种类型。这是有问题的,因为使用这些变量的任何下游 methods/functions 都可能被定义为明确接受 str
类型。 是否有公认的用法来解决此问题或强制执行 str
return 类型?
在 typeshed 中 getenv
的存根文件定义中,您可以发现 getenv
可以具有 return 类型的 Optional[str]
或 Union[str, T_]
取决于 default
kwarg 的用法。
目前我能看到的四个选项是:
- 定义任何下游操作以接受
Optional[str]
类型作为参数。这感觉不是特别正确,因为 function/method 的结构可能不符合 Optional
类型。即该操作没有理由将特定参数设为 None
.
- 对
getenv
使用 default
kwarg 并提供 str
默认值。这似乎更正确,但需要为 getenv
的每次使用设置一个默认值。我能看到的唯一问题是这样做可能会混淆不同环境中的测试或使用。
- 定义某种变量检查函数。这可能是一个函数,它接受要加载的环境变量的名称,显式 returns 一个字符串,如果环境变量不存在则引发错误。
- 将
getenv
编辑的值 return 的类型明确设置为 str。我真的不喜欢这样,因为它期望环境始终得到正确配置,根据我的经验,这不是一个好的假设。
在下面找到引发 mypy 错误的示例。
import os
SOME_VAR = os.getenv("SOME_VAR")
def some_func(val: str) -> None:
print(f"Loaded env var: {val}")
some_func(SOME_VAR)
以上引发mypy错误:
error: Argument 1 to "some_func" has incompatible type "Optional[str]"; expected "str"
tl;dr 如果您确定它始终存在,请使用 os.environ['SOME_VAR']
os.getenv
可以而且确实如此 return None
-- mypy 有助于显示您那里有一个错误:
>>> repr(os.getenv('DOES_NOT_EXIST'))
'None'
>>> repr(os.getenv('USER'))
"'asottile'"
或者,您可以通过两种不同的方式说服 mypy 它是您期望的类型:
- 利用断言:
x = os.getenv('SOME_VAR')
assert x is not None, x
# mypy will believe that it is non-None after this point
使用演员表:
from typing import cast
x = cast(str, os.getenv('SOME_VAR'))
# mypy will believe that it is a `str` after this point
(转换有一些缺点,因为它永远不会被检查,而断言可能会导致测试失败)
我建议 不要 忽略这个错误/解决它,而是使用 os.environ['SOME_VAR']
来处理你希望永远存在的东西,或者写一个条件来检查缺少时的错误情况
SOME_VAR
是可选的,因为它可以是 None
Return the value of the environment variable varname if it exists, or value if it doesn’t. value defaults to None.
如果环境变量不存在,您可以设置回退:
import os
SOME_VAR = os.getenv("SOME_VAR", "my fallback value")
def some_func(val: str) -> None:
print(f"Loaded env var: {val}")
some_func(SOME_VAR)
这将使 SOME_VAR
"not optional"
使用 os.getenv
检索环境变量时,默认行为 return 是 Optional[str]
的一种类型。这是有问题的,因为使用这些变量的任何下游 methods/functions 都可能被定义为明确接受 str
类型。 是否有公认的用法来解决此问题或强制执行 str
return 类型?
在 typeshed 中 getenv
的存根文件定义中,您可以发现 getenv
可以具有 return 类型的 Optional[str]
或 Union[str, T_]
取决于 default
kwarg 的用法。
目前我能看到的四个选项是:
- 定义任何下游操作以接受
Optional[str]
类型作为参数。这感觉不是特别正确,因为 function/method 的结构可能不符合Optional
类型。即该操作没有理由将特定参数设为None
. - 对
getenv
使用default
kwarg 并提供str
默认值。这似乎更正确,但需要为getenv
的每次使用设置一个默认值。我能看到的唯一问题是这样做可能会混淆不同环境中的测试或使用。 - 定义某种变量检查函数。这可能是一个函数,它接受要加载的环境变量的名称,显式 returns 一个字符串,如果环境变量不存在则引发错误。
- 将
getenv
编辑的值 return 的类型明确设置为 str。我真的不喜欢这样,因为它期望环境始终得到正确配置,根据我的经验,这不是一个好的假设。
在下面找到引发 mypy 错误的示例。
import os
SOME_VAR = os.getenv("SOME_VAR")
def some_func(val: str) -> None:
print(f"Loaded env var: {val}")
some_func(SOME_VAR)
以上引发mypy错误:
error: Argument 1 to "some_func" has incompatible type "Optional[str]"; expected "str"
tl;dr 如果您确定它始终存在,请使用 os.environ['SOME_VAR']
os.getenv
可以而且确实如此 return None
-- mypy 有助于显示您那里有一个错误:
>>> repr(os.getenv('DOES_NOT_EXIST'))
'None'
>>> repr(os.getenv('USER'))
"'asottile'"
或者,您可以通过两种不同的方式说服 mypy 它是您期望的类型:
- 利用断言:
x = os.getenv('SOME_VAR')
assert x is not None, x
# mypy will believe that it is non-None after this point
使用演员表:
from typing import cast x = cast(str, os.getenv('SOME_VAR')) # mypy will believe that it is a `str` after this point
(转换有一些缺点,因为它永远不会被检查,而断言可能会导致测试失败)
我建议 不要 忽略这个错误/解决它,而是使用 os.environ['SOME_VAR']
来处理你希望永远存在的东西,或者写一个条件来检查缺少时的错误情况
SOME_VAR
是可选的,因为它可以是 None
Return the value of the environment variable varname if it exists, or value if it doesn’t. value defaults to None.
如果环境变量不存在,您可以设置回退:
import os
SOME_VAR = os.getenv("SOME_VAR", "my fallback value")
def some_func(val: str) -> None:
print(f"Loaded env var: {val}")
some_func(SOME_VAR)
这将使 SOME_VAR
"not optional"