Python class 为具有不同数量的继承方法的继承设计
Python class design for inheritance with varied number of inherited methods
我正在为 SOAP API 构建 Python API 包装器。我需要设计一组 API classes,其中包含不同数量的动词动作(add
、get
、list
、remove
ETC。)。此外,由于 SOAP API 中对象的性质,这些对象还可能包含来自 (sync
、options
、apply
、restart
和 reset
)。每个动词的内部结构意味着很少有情况需要覆盖并且很容易被继承。我的问题是一些端点是单例的,或者出于某种原因可能只支持这些方法的一个子集。意思是:
端点A
get
仅
端点 B
add
、get
、list
、remove
apply
和 restart
端点 C
仅 add
和 get
端点D
add
、get
、list
、remove
apply
、restart
、reset
我有 100 多个端点。最契合一个共同主题:
add
、get
、list
、remove
但是,也有很多例外。
在我当前的设计中,所有端点都使用 Client
属性进行实例化,该属性控制线路上的 SOAP 连接、请求和响应。我正在寻找一种方法来灵活地创建 class 设计,允许我在不需要复制代码或无意中继承 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...
我在考虑 mixins,但如您所见,动词方法依赖于通用客户端。根据我的理解,mixins 应该只继承自 object
.
任何人都可以建议如何布置我的 class 设计以尽可能促进重用并避免缺乏灵活性吗?
如果端点支持,方法的实现对于所有端点都是相同的,我是否理解正确?在这种情况下,您可以使用一个小列表来解决它,该列表包含受支持的方法名称并被每个端点 subclass:
覆盖
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
这减少了将基本方法调整为每行一行 class 的工作量,并且仍然让您可以灵活地添加任何必要的代码。
我正在为 SOAP API 构建 Python API 包装器。我需要设计一组 API classes,其中包含不同数量的动词动作(add
、get
、list
、remove
ETC。)。此外,由于 SOAP API 中对象的性质,这些对象还可能包含来自 (sync
、options
、apply
、restart
和 reset
)。每个动词的内部结构意味着很少有情况需要覆盖并且很容易被继承。我的问题是一些端点是单例的,或者出于某种原因可能只支持这些方法的一个子集。意思是:
端点A
get
仅
端点 B
add
、get
、list
、remove
apply
和restart
端点 C
-
仅
add
和get
端点D
add
、get
、list
、remove
apply
、restart
、reset
我有 100 多个端点。最契合一个共同主题:
add
、get
、list
、remove
但是,也有很多例外。
在我当前的设计中,所有端点都使用 Client
属性进行实例化,该属性控制线路上的 SOAP 连接、请求和响应。我正在寻找一种方法来灵活地创建 class 设计,允许我在不需要复制代码或无意中继承 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...
我在考虑 mixins,但如您所见,动词方法依赖于通用客户端。根据我的理解,mixins 应该只继承自 object
.
任何人都可以建议如何布置我的 class 设计以尽可能促进重用并避免缺乏灵活性吗?
如果端点支持,方法的实现对于所有端点都是相同的,我是否理解正确?在这种情况下,您可以使用一个小列表来解决它,该列表包含受支持的方法名称并被每个端点 subclass:
覆盖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
这减少了将基本方法调整为每行一行 class 的工作量,并且仍然让您可以灵活地添加任何必要的代码。