有没有办法做"模板基类"在Python?

时间:2018-04-24 11:10:43

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

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

在C ++中,可以定义将从DerivedBase1继承的模板类Base2,创建该类型的对象并将其传递给ff:< / p>

// 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中实现相同的架构?

2 个答案:

答案 0 :(得分:0)

下面的代码只是为了表明它可以在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'>)
>>> 

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

答案 1 :(得分:0)

我为自己编写了一个玩具库,以便与元类一起玩。您可以使用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不同,这不会删除模板参数信息,并允许传递值和类型。