代码之家  ›  专栏  ›  技术社区  ›  user8510613

使基类中的特定接口可用于所有派生类

  •  1
  • user8510613  · 技术社区  · 6 年前

    我有一个基类和一个公共 fn 在里面。我想使层次结构系统中的所有类都可以调用,并且它们的 __call__ 把他们的作品翻译成 fn Class.__call__ = fn . 以下代码显示了我当前如何实现。

    class Base:
        def fn(self, *input):
            # ...
    
        __call__ = fn
    
    class Derived(Base):
        def fn(self, input):
            # ...
    
        __call__ = fn
    

    __召唤__ 在基类中,在 __召唤__ 的功能体,将其工作转换为 fn fn . 语义类似于“从基继承公共接口和实现,在这个公共接口中,每个派生类定义自己的实现版本”。

    然而,一些 fn 有不同的参数列表,不总是与基本的相同,就像我上面展示的情况一样。上面的代码可以工作,但我想一定有更好的解决方案,在层次结构系统的所有类中都没有重复定义。

    只在基类中使用一次,但是否使其可用于所有派生类?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Patrick Haugh    6 年前

    如果您使用的是Python版本>=3.6,你可以写一个 __init_subclass__ 方法 Base 类,该类指定 __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
    
        2
  •  0
  •   J_H    6 年前

    在您提供的示例中,不需要使用 __call__ . 已经有了一个非常好的机制,因为python将调用类构造函数。这么简单 def __init__(self, *args): 然后进行代码调用 fn

    您提到了不同的参数列表,但没有描述如何区分它们。如果这是一个简单的标准,比如 len(args) ,那么你所拥有的就足够了。如果它更复杂,您可能需要 **kwargs 在签名中,让每个方法只选择它识别的关键字参数。