我为特定类型创建了 Google API
Resource
类(在本例中为 blogger
)。
from googleapiclient.discovery import Resource, build
def get_google_service(api_type) -> Resource:
credentials = ...
return build(api_type, 'v3', credentials=credentials)
def blog_service():
return get_google_service('blogger')
def list_blogs():
return blog_service().blogs()
使用
list_blogs
函数时会出现问题。
由于我提供了特定的服务名称,我知道 blog_service
的返回值有一个 blogs
方法,但我的 IDE 无法识别它。
有没有办法注释 blog_service
函数(或代码的任何其他部分)以告知我的 IDE blogs
方法的存在?
这里的问题是
Resource
类动态根据底层API提供的集合设置任意属性/方法。
在您的情况下,显然有一个
blogs
集合,这意味着 blogs
方法是在该 Resource
对象上动态构造的。
期望静态类型注释,当你的类型被动态创建时是一个艰巨的任务。 (我认为这是
google-api-python-client
的维护者甚至不关心该包中的类型提示的原因之一。)
但是,根据您对这些功能的目标,您可以通过使用 协议来改善您的 IDE 体验。
如果您知道您的
blog_service
函数返回一个具有 blogs
方法的对象,您可以定义相应的 协议。这个问题当然被解决了,因为无论 blogs
方法返回什么,也可能有任意方法。但取决于这对您是否重要,您可以再次应用相同的原则。
Resource
本身实际上似乎只有很少的公共方法,基本上只有 close
和上下文管理器协议。因此,您可以在某种基本协议中进行模拟,并使用继承来构造不同的资源协议。
这里举个例子来说明:
from typing import Any, Protocol, Self
from googleapiclient.discovery import build # type: ignore[import]
class ResourceProtocol(Protocol):
def close(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(self, *args: Any) -> None: ...
class BloggerProtocol(ResourceProtocol):
def blogs(self) -> Any: ...
def get_google_service(api_type: str) -> Any:
credentials = ...
return build(api_type, 'v3', credentials=credentials)
def blog_service() -> BloggerProtocol:
return get_google_service('blogger') # type: ignore[no-any-return]
def list_blogs() -> Any:
return blog_service().blogs()
(请注意,这些都是 literal 省略号
...
。此外,如果您使用的是 Python <3.11
,您应该能够从 Self
导入
typing_extensions
。)
现在您的 IDE 应该能够检测到
blog_service
返回的对象具有 blogs
方法 并且 可以用作上下文管理器(使用 with
)。
请注意,我将
blogs
的返回类型注释为 Any
,因为我不知道它应该返回什么类型。