我有一个带有公共fn
的基类。我想使层次结构系统中的所有类都可调用,并且它们的__call__
实际上将其工作转换为fn
,其语义类似于Class.__call__ = fn
。以下代码显示了我当前的实现方式。
class Base:
def fn(self, *input):
# ...
__call__ = fn
class Derived(Base):
def fn(self, input):
# ...
__call__ = fn
我知道有一种设计只能在基类和__call__
的函数体中定义一个__call__
,以将其工作转换为fn
,每个派生类实现自己的fn
。语义就像“继承自Base的公共接口并实现,在此公共接口中,每个Derived类定义其自己的实现版本”。
但是,有些fn
具有不同的参数列表,与我的上面所示的情况并不总是与基本列表相同。上面的代码可以工作,但是我想必须有更好的解决方案,而不必在层次结构系统的所有类中都重复定义。
因此,在基类中是否仅一次特定了__call__
,但是使它可用于所有派生类?
答案 0 :(得分:1)
如果您使用的Python版本> = 3.6,则可以编写Base
类的__init_subclass__
方法,该方法将子类的__call__
属性分配为等于其fn
属性:
class Base:
def fn(self, *args):
return args
__call__ = fn
def __init_subclass__(cls):
cls.__call__ = cls.fn
class Derived(Base):
def fn(self, arg):
print("In derived")
return arg
Base()(1, 2, 3)
# (1, 2, 3)
Derived()(1)
# In derived
# 1
如果您使用的是旧版本的Python,则可以通过元类实现类似的效果。
class BaseMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
cls.__call__ = cls.fn
class Base(metaclass=BaseMeta):
def fn(self, *args):
return args
class Derived(Base):
def fn(self, arg):
print("In derived")
return arg
答案 1 :(得分:0)
在您提供的示例中,无需使用__call__
。已经存在一个非常好的机制,因为python将调用类构造函数。因此,只需def __init__(self, *args):
,然后适当地调用该代码即可fn
。
您提到了不同的参数列表,但没有描述如何区分它们。如果这是一个简单的标准,例如len(args)
,那么您所拥有的就足够了。如果更复杂,则可能需要将**kwargs
放在签名中,并让每种方法只挑选它可以识别的关键字参数。