python - Python基类的动态覆盖方法
问题描述
我得到了一个 Python 基类,它定义了一个我必须在派生类中实现的接口。在基类中,每个方法都定义为 throws 的存根NotImplementedError
。
有很多这样的方法,它们的名称大多非常规则,形式为<Operation><Type>
. 原则上,绝大多数可以通过分派到一个方法来实现,该方法采用"<Operation>"
和"<Type>"
,从方法名称解析,作为参数。我想做这样的事情来避免样板。但是,有少数方法需要显式覆盖。
class Base(object):
...
# 'Regular' methods - the majority of the interface
def CreateObj1(self, arg):
raise NotImplementedError()
def DeleteObj1(self, arg):
raise NotImplementedError()
# etc.. for a number of such operations
# for many type Obj1, Obj2, ...
# A few methods that don't fit the above pattern
def SpecialMethod1(self, arg):
raise NotImplementedError()
...
class Derived(Base):
...
def _impl(self, operation_name, object_type, arg):
# With this I am essentially able to implement
# all of the 'regular' methods
...
def CreateObj1(self, arg):
return self._impl('Create', 'Obj1', arg)
def DeleteObj1(self, arg):
return self._impl('Delete', 'Obj1', arg)
def SpecialMethod1(self, arg):
# This still needs an explicit implementation
...
...
我可以像上面那样实现它,但我不想为“常规”方法编写所有显式委托,因为它增加了一个在接口扩展时需要维护的地方。
我的第一个想法是定义一个__getattr__
方法,但问题是基本存根方法“获胜”并且__getattr__
没有被调用。我想我也许可以让它工作,__getattribute__
但我以前从来不需要使用它并且很谨慎,因为我知道滥用它很容易陷入混乱。
__getattribute__
听起来像是正确的方法还是我可能会错过其他方法?
如果这是正确的方法,我是否可以遵循任何特定模式来确保我正确使用它?
处理少数无法动态覆盖且需要在派生类中显式实现的方法的最佳方法是什么?
解决方案
您可以使用元类(小心处理)
class BaseMeta(type):
def get_default_impl(base_attr, subject="Obj1"):
# modify this method
action, _ = base_attr.split(subject)
def _default(self, arg):
return self._impl(action, subject, arg)
return _default
def __new__(mcs, name, bases, attrs):
# print("attrs:", attrs, "base:", bases)
for base in bases:
for base_attr in dir(base):
if base_attr.endswith("Obj1"): # modify this
attrs.setdefault(base_attr, mcs.get_default_impl(base_attr))
def _impl(self, operation_name, object_type, arg):
raise NotImplementedError()
attrs.setdefault("_impl", _impl)
return super().__new__(mcs, name, bases, attrs)
class Derived(Base, metaclass=BaseMeta):
def _impl(self, operation_name, object_type, arg):
print("got op:{}, obj: {}, arg: {}".format(operation_name, object_type, arg))
您将需要根据基类上的方法的定义方式if base_attr.endswith("Obj1"):
进行修改。get_default_impl
我已经使用了您发布的示例。
推荐阅读
- javascript - 登录后在 ASP.NET 页面中隐藏导航
- mongodb - 元数据升级未在 2 个节点中进行(mongo 2.6 到 mongo 3.0)
- python - Pytest-Flask 无法导入名称“create_app”
- reactjs - 本地主机存储
- python - 如何使用原始 DF 中的索引创建新的 DataFrame 重复行
- swiftui - SwiftUI - 无法在工作表底部填充屏幕
- c - 具有动态维度的向量不是来自辅助函数的正确 scanf()
- javascript - Sweetalert2 模态在图像出现在模态之前短暂加载
- r - R data.table中双点`..`的错误
- javascript - ES2020 可选链:a?.().b 和 a()?.b 和 a?.()?.b 有什么区别