【问题标题】:Is there a way to do "template base class" in Python?有没有办法在 Python 中做“模板基类”?
【发布时间】:2018-04-24 11:10:43
【问题描述】:

假设有两个类Base1Base2 继承自一个公共基类Base。还有一些函数 ff 可以与 Base 一起使用。

在 C++ 中,可以定义一个模板类 Derived,它将继承自 Base1Base2,创建该类型的对象并将它们传递给 ff

// Given
struct Base1 : Base { };
struct Base2 : Base { };
void ff(const Base& base) { }

// you can do...
template < typename BB >
struct Derived : public BB { /* implement here what is common to both Derived1 and Derived2 */ };
struct Derived1 : public Derived<Base1> { /* implement here what is specific to Derived1 but not Derived2 */ };
struct Derived2 : public Derived<Base2> { /* implement here what is specific to Derived2 but not Derived1 */ };

// ... and live your life in peace with: 
Derived1 d1;
Derived2 d2;
ff(d1);
ff(d2);

问题是如何在 Python3.6 中实现相同的架构?

【问题讨论】:

  • 我认为多重继承并不是你想的那样。
  • 它目前的意思是我认为的意思。在尝试构建这样的架构时,它可能会被用于 Python 的技巧中。但是,是的,我没有提到这些技巧,因为它们并不能完全解决我的问题,也许我应该从标签中删除它。谢谢。
  • 你最好询问你真正想要通过它实现的目标(在 python 中!)。尝试直接将代码从一种语言翻译成另一种语言通常会带来更多必要的困难,因为同一问题的解决方案可能完全不同
  • 是的,这是可能的,而且它可能比 C++ 方式更简单,因为 Python 自然允许动态类型、鸭子类型和猴子补丁(这些名称只需要 google)。

标签: c++ python-3.x templates


【解决方案1】:

我为自己编写了一个玩具库来玩元类。您可以通过pip install type_templating from PyPI 获得它。源自one of its tests

from type_templating import Template, TemplateParameter

class Base: pass
class Base1(Base): pass
class Base2(Base): pass

BB = TemplateParameter('BB')

# Derived is a template taking one argument
class Derived(BB, metaclass=Template[BB]):
    # implement here what is common to both Derived1
    # and Derived2. The template argument is accessible as
    # `self.__args[BB]`
    pass

class Derived1(Derived[Base1]): pass
class Derived2(Derived[Base2]): pass

与内置 typing.Generic 不同,这不会删除模板参数信息,并允许传递值和类型。

【讨论】:

    【解决方案2】:

    以下代码只是为了表明它在 Python 中是可能的,但恕我直言,它并不是真正的 Pythonic,因为它只是在模仿 C++ 模板。

    >>> class Base:
        pass
    
    >>> class Base1(Base):
        pass
    
    >>> class Base2(Base):
        pass
    
    >>> def templated(base):     # a Python decorator to mimic the C++ templating engine
        def outer(clazz):
            class Inner(base):
                _base = base      # a class attribute that will be tested later
            return Inner
        return outer
    
    >>> class Derived:
        pass         # implement what is common to both Derived1 and Derived2
    
    >>> @templated(Base1)
    class Derived1:
        pass         # implement what is specific to Derived1
    
    >>> Derived1._base        # to prove that it extends Derived<Base1> (C++ like syntax)
    <class '__main__.Base1'>
    >>> Derived1.__mro__      # base classes
    (<class '__main__.templated.<locals>.outer.<locals>.Inner'>, <class '__main__.Base1'>,
    <class '__main__.Base'>, <class 'object'>)
    >>> 
    

    但在任何真实的例子中,肯定会有更简单的方法......

    【讨论】:

    • 你把Derived1的内容完全丢弃在这里
    猜你喜欢
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多