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

Python中使用第三方类、抽象类和工厂类时简化长类型提示的方法

解决多云密钥管理器抽象方法的类型提示冗余问题

当前开发的Python包需要对接Azure、GCP等云平台的密钥管理器,通过抽象类_SecretManager统一接口,工厂类创建对应实例。但抽象方法_get_secret_manager的类型提示存在问题:如果用Union枚举所有云客户端类型,扩展到大量云提供商时会非常繁琐;尝试将返回类型设为_SecretManager又会导致mypy报错,因为实际返回的是云服务商的客户端实例,并非自定义的_SecretManager子类。

解决方案:使用泛型(Generics)动态指定返回类型

通过Python的泛型特性,让抽象类支持动态定义_get_secret_manager的返回类型,每个子类只需指定对应云平台的客户端类型即可,无需修改抽象类的类型提示,完美解决扩展性问题。

修改后的完整代码

from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
from google.cloud.secretmanager import SecretManagerServiceClient
from azureml.core import Keyvault

# 定义类型变量,用于表示不同云平台的密钥管理器客户端类型
T = TypeVar('T')

class _SecretManager(ABC, Generic[T]):
    """ABC Class for Cloud Secret Managers like Keyvault or GCP Secret Manager"""

    def __init__(self) -> None:
        self.manager: T = self._get_secret_manager()

    @abstractmethod
    def _get_secret_manager(self) -> T:
        pass

    @abstractmethod
    def _get_secret(self, name: str) -> str:
        pass


class _AzureKeyVault(_SecretManager[Keyvault]):
    """_SecretManager Subclass for getting secrets from azure keyvault"""

    def _get_secret_manager(self) -> Keyvault:
        return Keyvault()

    def _get_secret(self, name: str) -> str:
        return self.manager.get_secret(name)


class _GCPSecretManager(_SecretManager[SecretManagerServiceClient]):
    """_SecretManager Subclass for getting secrets from GCP Secret Manager"""

    def _get_secret_manager(self) -> SecretManagerServiceClient:
        return SecretManagerServiceClient()

    def _get_secret(self, name: str) -> str:
        # 实际方法可能不同,这里仅作示例
        return self.manager.fetch_secret(name)


class _SecretManagerFactory:
    """Factory for creating _SecretManager"""

    def __init__(self) -> None:
        self._managers = {"azure": _AzureKeyVault, "gcp": _GCPSecretManager}

    def create_secret_manager(self, cloud_provider: str, **kwargs) -> _SecretManager:
        try:
            manager_cls = self._managers[cloud_provider]
        except KeyError:
            raise ValueError(f"No secret manager available for cloud provider: {cloud_provider}")
        return manager_cls(**kwargs)

关键改动说明

  1. 引入泛型支持:导入TypeVar和Generic,定义类型变量T来代表任意云平台的客户端类型。
  2. 抽象类泛型化:_SecretManager继承Generic[T],将self.manager的类型标注为T,_get_secret_manager的返回类型也设为T。
  3. 子类指定具体类型:每个子类继承_SecretManager时,通过[具体客户端类型]指定泛型参数,比如_AzureKeyVault(_SecretManager[Keyvault]),同时在_get_secret_manager方法中明确返回对应类型。
  4. 优化工厂类:添加cloud_provider的类型提示,完善错误信息,同时加入GCP的管理器映射。

这样修改后,mypy可以准确推断每个子类中self.manager的类型,不会再出现属性不存在的报错;后续扩展新的云提供商时,只需创建新的子类并指定对应客户端类型即可,完全不需要修改抽象类的类型提示,扩展性拉满。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:32:51