Python 3.x Python类设计,用于使用不同数量的继承方法进行继承
我正在为SOAP API构建Python API包装器。我需要设计一组包含不同数量动词动作的API类(Python 3.x Python类设计,用于使用不同数量的继承方法进行继承,python-3.x,inheritance,multiple-inheritance,Python 3.x,Inheritance,Multiple Inheritance,我正在为SOAP API构建Python API包装器。我需要设计一组包含不同数量动词动作的API类(add,get,list,remove等)。此外,由于SOAP API中对象的性质,这些对象还可能包含来自(sync,选项,应用,重新启动和重置)子集的附加方法。每个动词的内部结构都意味着很少有情况需要重写,并且很容易被继承。我的问题是有些端点是单例的,或者出于任何原因,可能只支持这些方法的一个子集。意思是: 端点 仅获取 端点B 添加,获取,列表,删除 应用和重新启动 端点C 仅添加
add
,get
,list
,remove
等)。此外,由于SOAP API中对象的性质,这些对象还可能包含来自(sync
,选项
,应用
,重新启动
和重置
)子集的附加方法。每个动词的内部结构都意味着很少有情况需要重写,并且很容易被继承。我的问题是有些端点是单例的,或者出于任何原因,可能只支持这些方法的一个子集。意思是:
端点
仅获取
,添加
,获取
,列表
删除
和应用
重新启动
和仅添加
获取
,添加
,获取
,列表
删除
,应用
,重新启动
重置
,添加
,获取
,列表
删除
Client
属性实例化,该属性控制连接上的SOAP连接、请求和响应。我正在寻找一种灵活创建类设计的方法,允许我插入方法,而无需重复代码或无意中继承API端点不支持的方法
平面继承是有问题的,因为对于方法的所有排列,我没有足够的灵活性
BaseAPI(object):
def __init___(self, client):
self.client = client
ChildAPI(BaseAPI):
def __init___(self, client):
super().__init__(client)
def get(self, **kwargs):
soap_method = methodcaller("".join(["get", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return resp
def list(self, **kwargs):
soap_method = methodcaller("".join(["list", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return stuff
# same for add and remove...
EndpointA(BaseAPI):
def __init___(self, client):
super().__init__(client)
# now i have a problem as i only wanted the get method...
EndpointD(BaseAPI):
def __init___(self, client):
super().__init__(client)
# I have all the methods I wanted...
我在考虑mixin,但是正如您所看到的,动词方法依赖于公共客户机。根据我的理解,mixin应该只从对象继承
有人能建议如何布置我的类设计,以尽可能促进重用,并避免缺乏灵活性吗?我是否正确地理解,如果端点支持该方法,那么该方法的实现对于所有端点都是相同的?在这种情况下,您可以使用一个小列表来解决这个问题,该列表包含受支持的方法名称,并被每个端点子类覆盖:
import functools
class BaseAPI:
def __init___(self, client):
self.client = client
class ChildAPI(BaseAPI):
supported_methods = ["add", "get", "list", "remove", "apply", "restart", "reset"]
@classmethod
def assert_supported(cls, func):
"""Decorator looks up func's name in self.supported_methods."""
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if func.__name__ not in self.supported_methods:
raise AttributeError("This Endpoint does not support this method.")
return func(self, *args, **kwargs)
return wrapper
# implementation of methods here, each decorated with @assert_supported
@assert_supported
def get(self, **kwargs):
soap_method = methodcaller("".join(["get", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return resp
@assert_supported
def list(self, **kwargs):
soap_method = methodcaller("".join(["list", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return stuff
class EndpointA(BaseAPI):
supported_methods = ["get"]
class EndpointB(BaseAPI):
supported_methods = ["add", "get", "list", "remove", "apply", "restart"]
class EndpointC(BaseAPI):
supported_methods = ["add", "get"]
class EndpointD(BaseAPI):
pass # no change to supported_methods => all of them
这减少了将基本方法调整为每个类一行的工作量,并且仍然使您能够灵活地添加任何必要的代码。这看起来是支持这一点的最可行的方法。我能看到的唯一缺点是IDE提供的方法,但代价很小。很想测试一下。@1:对。您仍然可以将“u”放在名称前面,在大多数自动完成场景中,首先应该隐藏\u支持的\u方法@2:两者都是可能的,但我个人更喜欢将decorator函数直接保留在它应该使用的地方,这只在这个类中,因为它强烈地依赖于这个类的支持的\u方法属性,但我的意思是更多关于自动完成中出现的add
,当端点不支持时。再次,与我现在的处境相比,这是一个很好的问题。。。建议的解决方案对我来说非常好。我只剩下一个极端情况,即少数端点需要不符合基本方法签名的方法,因此重写实际上是一个重载,它违反了LSP。我正在考虑为这些扩展BaseAPI
。我不确定用Python如何更好地处理这个问题。啊,是的,对不起,我把“方法”和“支持的方法”属性混淆了。我正在考虑另一个decorator,如果不受支持,它将从类中删除该方法,但decorator无法访问该类。或者至少我没有让它起作用。Hm LSP。。。我承认我不得不用谷歌搜索:D,但如果你真的需要它,也许有一种方法可以让你的重载只在签名中添加关键字args?