Mar*_*jko 2 python typing dynamic-typing
我想为作为参数传递的 Python 类型正确添加类型。例如,假设我们想向以下函数添加类型:
def do_something_based_on_types(
...
type_name: str,
str_to_type_mapping: Dict[str, Any], # what instead of Any?
):
...
object = str_to_type_mapping[type_name]()
...
Run Code Online (Sandbox Code Playgroud)
我们希望传递一个映射到str类型,基于该映射我们希望构造选定类的对象。对于这种情况,正确的类型是什么(而不是Any在代码示例中使用)。
你的例子本质上是非常动态的。由于 Python 类型注释的主要目的是支持静态分析,因此它们可以为我们提供的功能是有限的。但是,我确实认为我们可以做得更好Any!
(注意:为了防止混淆,我将在代码片段中引用名为 的变量object,my_object当我使用 时object,我指的是 Python 类型)。
由于您提到提供的字典中的值应该是可以启动的类型,因此合理的类型注释将是 或Dict[str, Type[object]],Dict[str, Type]其中后者相当于Dict[str, Type[Any]]。第一个是最严格的,它将限制类型检查器允许您对my_object变量执行的操作。第二种方法仅比 plain 稍微好一些Any,尽管它会在调用者意外提供实例而不是类型时发出警告。
从您提供的代码片段来看,使用字典值的唯一方法是创建一个新实例。类型并不是唯一可以做到这一点的东西。实际上,任何采用零参数并返回对象的可调用函数(普通函数、类方法)也足够了。因此,使用Callable[[], object]将为函数的调用者提供更大的灵活性,并且在传递不具有零参数构造函数的类型时发出警告。我更喜欢这个,Type因为它看起来更安全,也更符合 Python 鸭子类型的精神。
这两种解决方案都有一个限制,即在您的函数内部,我们对 的类型一无所知my_object。在一般情况下,isinstance每次执行对象类型不支持的操作时,我们都会“被迫”进行检查。但是,也许在您的用例中,单个字典不应该只包含任何类型。可能是这样的:
MyBase。对于情况(1),我们可以object用 type 替换 type MyBase。类型检查器应该能够确保所支持的操作MyBase可以安全使用,并在提供的字典包含其他类型时发出警告。
对于情况(2),typing.Protocol可以帮助我们。您可以使用所需的操作定义自定义协议,并将其添加到类型注释中:
class MyCustomProto(Protocol):
foo: int
def bar(self) -> str: ...
Run Code Online (Sandbox Code Playgroud)
现在类型检查器应该知道my_object应该具有整数属性
和返回字符串的foo方法。bar请注意,它已添加到 Python 3.8 中,并且可通过Typing-extensionsProtocol包用于以前的版本。
与你的问题没有直接关系,但如果你只使用字典来阅读,你应该考虑Dict用Mapping类型替换。这允许调用者提供除 dict 子类之外的任何映射类型(实际上不太可能发生)。但更重要的是,它会在意外修改提供的映射时向您发出警告,这可能会导致难以发现错误。因此,我的最终建议是Mapping[str, Callable[[], <X>],<X>成为object或MyCustomProto之一MyBase。
| 归档时间: |
|
| 查看次数: |
3496 次 |
| 最近记录: |