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

Python中如何正确定义要求类属性的Protocol接口?

问题分析与解决方案

你的核心问题是协议定义和传入的对象类型不匹配:你用typing.Protocol定义的是「实例对象」需要具备的成员,但调用函数时传入的是MyHandler这个类本身(而非类的实例),所以类型检查工具会提示类型不兼容。

解决方案1:让协议适配类对象(适合直接传类的场景)

如果你的设计就是要直接传入类而非实例,需要修改协议,明确它描述的是类对象的结构,同时函数参数类型指定为typing.Type[协议类型]:

import typing
import re

class HandlerProtocol(typing.Protocol):
    """描述类对象的协议"""
    pattern: re.Pattern

    @staticmethod
    def handle(match: re.Match) -> str:
        pass

# 函数参数接收实现了HandlerProtocol的类
def f(obj: typing.Type[HandlerProtocol], text: str):
    output = []
    for match in re.finditer(obj.pattern, text):
        output.append(obj.handle(match))
    return output

class MyHandler:
    pattern = re.compile("hello world")

    @staticmethod
    def handle(match: re.Match) -> str:
        return "hi there"

# 传入类不再报错
print(f(MyHandler, 'hello world, what a nice morning!'))

解决方案2:改为传入实例(符合Protocol默认的实例描述逻辑)

如果应该传入类的实例,需要调整协议和实现类,确保实例能提供pattern和handle成员:

import typing
import re

class Handler(typing.Protocol):
    """描述实例对象的协议"""
    @property
    def pattern(self) -> re.Pattern:
        ...

    def handle(self, match: re.Match) -> str:
        ...

def f(obj: Handler, text: str):
    output = []
    for match in re.finditer(obj.pattern, text):
        output.append(obj.handle(match))
    return output

class MyHandler:
    _pattern = re.compile("hello world")

    @property
    def pattern(self) -> re.Pattern:
        return self._pattern

    def handle(self, match: re.Match) -> str:
        return "hi there"

# 传入类的实例
print(f(MyHandler(), 'hello world, what a nice morning!'))

为什么原来的写法会报错?

typing.Protocol默认描述的是实例对象的结构,而你传入的MyHandler是类(类型为Type[MyHandler]),和协议要求的Handler实例类型不匹配。移除pattern属性后,类型检查工具可能因为缺少明确的属性约束而放松判断,但这并不是正确的解决方式。

内容的提问来源于stack exchange,提问作者Green 绿色

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:55:54