Python 3.x Python类设计,用于使用不同数量的继承方法进行继承

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 仅添加

我正在为SOAP API构建Python API包装器。我需要设计一组包含不同数量动词动作的API类(
add
get
list
remove
等)。此外,由于SOAP API中对象的性质,这些对象还可能包含来自(
sync
选项
应用
重新启动
重置
)子集的附加方法。每个动词的内部结构都意味着很少有情况需要重写,并且很容易被继承。我的问题是有些端点是单例的,或者出于任何原因,可能只支持这些方法的一个子集。意思是:

端点

  • 仅获取
端点B

  • 添加
    获取
    列表
    删除
  • 应用
    重新启动
端点C

  • 仅添加
    获取
端点

  • 添加
    获取
    列表
    删除
  • 应用
    重新启动
    重置
我有100多个端点。最符合以下共同主题:

  • 添加
    获取
    列表
    删除
然而,也有许多例外

在我当前的设计中,所有端点都使用
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?