You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为遍历对象可迭代属性的生成器函数添加正确Python类型标注?

解决Python生成器函数的类型标注问题

要让mypy能检测出传入不存在属性的错误,你需要通过类型约束明确泛型T必须包含指定的可迭代属性。根据你的需求,有两种合适的方案:

方案1:使用属性访问器实现通用静态检查

将函数的属性名参数替换为属性访问器(Callable),让mypy能静态验证属性是否存在、类型是否匹配。这是通用场景下的最优解。

from typing import Iterator, TypeVar, Callable, Iterable

T = TypeVar('T')
S = TypeVar('S')

def iter_attribute(objects: list[T], get_attribute: Callable[[T], Iterable[S]]) -> Iterator[S]:
    for obj in objects:
        yield from get_attribute(obj)

# 示例使用
class A:
    def __init__(self):
        self.a = [1, 2, 3]

objs = [A(), A()]
# 正确调用:访问存在的属性`a`
for item in iter_attribute(objs, lambda x: x.a):
    print(item)

# 错误调用:mypy会直接报错,因为`A`类不存在`b`属性
# for item in iter_attribute(objs, lambda x: x.b):
#     print(item)

方案2:针对固定属性名用Protocol约束

如果你的生成器只处理某个固定名称的属性,可以定义Protocol来强制约束泛型T必须包含该属性,且属性是可迭代的S类型。

from typing import Protocol, Iterator, TypeVar, Iterable

S = TypeVar('S', covariant=True)

# 定义协议:要求类型包含名为`target_attr`的可迭代属性
class HasTargetAttr(Protocol[S]):
    target_attr: Iterable[S]

T = TypeVar('T', bound=HasTargetAttr[S])

def iter_attribute(objects: list[T]) -> Iterator[S]:
    for obj in objects:
        yield from obj.target_attr

# 示例使用
class ValidClass:
    def __init__(self):
        self.target_attr = [1, 2, 3]

# 正确调用
for item in iter_attribute([ValidClass(), ValidClass()]):
    print(item)

# 错误调用:mypy会报错,因为类没有`target_attr`属性
# class InvalidClass:
#     def __init__(self):
#         self.other_attr = [4,5,6]
# for item in iter_attribute([InvalidClass(), InvalidClass()]):
#     print(item)

注意:字符串属性名的局限性

如果坚持用字符串作为属性名参数,由于字符串是动态值,mypy无法进行静态检查(除非用Literal限定允许的属性名,但会让函数失去通用性)。因此不推荐这种写法,除非是动态场景下的必要选择。

内容的提问来源于stack exchange,提问作者Ingo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:02:08