python 类型提示应该如何要求一个值具有给定的属性? [英] How should a python type hint require that a value has a given attribute?

查看:20
本文介绍了python 类型提示应该如何要求一个值具有给定的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个像这样的简单函数:

Let's say I have a simple function like this:

def foo(a: Any):
    return a.bar + a.baz

我想将类型提示从 Any 更改为需要(好吧,建议,因为它是一种 hint 类型)a 提供 barbaz 属性.应该改成什么?

I would like to change the type hint from Any to one that requires (well, suggests, given that it is a type hint) that a provides the bar and baz attributes. What should it be changed to?

推荐答案

这正是 协议是为了.简而言之,Protocols 允许您使用 structural 而不是 nominal 子类型.对于名义子类型,如果 A 显式继承或扩展 B,则类型 A 是 B 的子类型.对于结构子类型,如果类型 A 具有与 B 相同的方法和属性签名"(有一些限制),则类型 A 是 B 的子类型.

This is exactly what Protocols are for. In short, Protocols let you use structural instead of nominal subtyping. With nominal subtyping, type A is a subtype of B if A explicitly inherits or extends B. With structural subtyping, type A is a subtype of B if it has the same method and attribute "signatures" as B (with some restrictions).

例如:

# If you're using Python 3.8+
from typing import Protocol

# If you need to support older versions of Python,
# pip-install the 'typing_extensions' module and do:
from typing_extensions import Protocol

class SupportsBarBaz(Protocol):
    bar: int
    baz: int

class MyUnrelatedClass1:
    def __init__(self, bar: int, baz: int) -> None:
        self.bar = bar
        self.baz = baz

class MyUnrelatedClass2:
    def __init__(self, bar: int, baz: int, blah: str) -> None:
        self.bar = bar
        self.baz = baz
        self.blah = blah

class MyUnrelatedClass3:
    def __init__(self, bar: str, baz: str, blah: str) -> None:
        self.bar = bar
        self.baz = baz
        self.blah = blah

def foo(a: SupportsBarBaz) -> int:
    return a.bar + a.baz

# These both type-check, even though there's no explicit relationship
# between 'SupportsBarBaz' and these two classes
foo(MyUnrelatedClass1(1, 2))
foo(MyUnrelatedClass2(1, 2, "abc"))

# But this doesn't type-check, since 'bar' and 'baz' are both strs here
foo(MyUnrelatedClass3("a", "b", "c"))

您可以在 mypy 文档中找到有关使用协议的更多信息.该页面中的信息都符合 PEP,所以那里的信息应该都适用于其他类型检查器,假设他们已经完成了自己对协议的支持.

You can find more information about using Protocols in the mypy docs. The information in that page is all compliant with the PEP, so the info there should all apply to other type checkers, assuming they've finished implementing their own support for Protocols.

您还可以在 typeshed,Python 标准库的类型提示存储库.

不过,我认为只有当您真正打算在代码中使用静态分析时,这一切才重要.如果没有,您可以做一些更简单的事情,只需为 Any 定义一个自定义类型别名,记录该别名应该"的含义,并使用该别名而不是成熟的协议.对于静态分析/自动完成工具/等而言,该别名几乎完全无用,但人类阅读评论通常没有问题.

Though, I suppose this all matters only if you actually intend on using static analysis in your code. If not, you could maybe do something simpler and just define a custom type alias to Any, document what that alias is "supposed" to mean, and use that alias instead of a full-fledged protocol. That alias would be almost completely useless for the purposes of static analysis/autocompletion tools/etc, but humans generally have no issues reading comments.

这篇关于python 类型提示应该如何要求一个值具有给定的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆