认为我们有Template method pattern继承方案。我正在使用请求库的一个示例
import abc
import json
import requests
from typing import Dict, Any
class Base(abc.ABC)
@abc.abstractmethod
def call(self, *args, **kwargs) -> requests.Response:
raise NotImplementedError
def safe_call(self, *args, **kwargs) -> Dict[str, Any]:
try:
response = self.call(*args, **kwargs)
response.raise_for_status()
return response.json()
except json.JSONDecodeError as je: ...
except requests.exceptions.ConnectionError as ce: ...
except requests.exceptions.Timeout as te: ...
except requests.exceptions.HTTPError as he: ...
except Exception as e: ...
return {"success": False}
class Derived(Base):
def call(self, url: str, json: Dict[str, Any], timeout: int, retries: int) -> requests.Response:
# actual logic for making the http call
response = requests.post(url, json=json, timeout=timeout, ...)
return response
它将像
executor = Derived()
response = executor.safe_call(url='https://example.com', json={"key": "value"}, ...)
有没有办法将Derived.call
的签名附加到Derived.safe_call
上,这样现代的IDE自动完成和类型检查就可以工作了?
因为这看起来非常像一个装饰器模式,所以我尝试在__init__
中使用functools.update_wrapper
,但在
AttributeError: 'method' object has no attribute '__module__'
我确实有一些选择,但我找不到关于这个问题的任何建议
.pyi
,并将其与主代码一起维护李>class Derived(Base):
def safe_call(self, url: str, json: Dict[str, Any], timeout: int, retries: int) -> Dict[str, Any]: ...
将设计完全更改为其他设计
(编辑:添加后第一个答案)(Ab)使用@typing.overload
class Derived(Base):
@typing.overload
def safe_call(self, url: str, json: Dict[str, Any], timeout: int, retries: int) -> Dict[str, Any]:
...
def call(self, url: str, json: Dict[str, Any], timeout: int, retries: int) -> requests.Response:
# actual logic for making the http call
response = requests.post(url, json=json, timeout=timeout, ...)
return response
我知道你想做什么,但我认为沿着这条路走可能是个错误,因为它会破坏Liskov Substitution Principle
目前,抽象类
Base
定义了一个接口,在接口的具体实现中,方法Base.call
可以使用任何位置或关键字参数调用,而不会在运行时引发错误。从理论上看,在Derived
类中call
的具体实现不满足此接口。如果使用>;4个参数,用<;4个参数,或使用非url
、json
、timeout
或retries
的关键字参数调用,将在运行时引发错误Python仍然允许您在运行时实例化
Derived
的实例,因为它只检查是否存在与Base
中定义的抽象方法同名的方法。它不会在实例化具体实现时检查抽象方法的签名兼容性,并且尝试这样做将非常困难。但是,某些类型检查器可能会抱怨派生类中的签名比基类中的签名更不允许。此外,理论原则本身也很重要我想应该是这样的。这里要注意两件事:
safe_call
和call
方法都已成为私有方法,因为它们是设计为不直接使用的实现细节李>call
和safe_call
的签名,以便它们只接受关键字参数李>如果希望在
_call
的具体实现中使用参数的默认值,请注意,可以使用kwargs.get(<arg_name>, <default_val>)
而不是kwargs[<arg_name>]
相关问题 更多 >
编程相关推荐