Metaclass to parametrize Inheritance

点点圈 提交于 2019-12-03 11:04:28

问题


I've read some tutorials on Python metaclasses. I've never used one before, but I need one for something relatively simple and all the tutorials seem geared towards much more complex use cases. I basically want to create a template class that has some pre-specified body, but takes its base class as a parameter. Since I got the idea from C++/D templates, here's an example of what the code I want to write would look like in C++:

template<class T>
    class Foo : T {
        void fun() {}
    }

回答1:


Although it certainly can be done with metaclasses, you can do what you want without them because in Python classes are themselves objects. The means that—surprisingly—essentially nothing more than an almost one-to-one translation of the C++ code is required. Besides being relatively uncomplicated because of this, it'll also work without modification in both Python 2 & 3.

def template(class_T):
    """Factory function to create subclasses of class_T."""

    class Foo(class_T):
        def fun(self):
            print('%s.fun()' % self.__class__.__name__)

    Foo.__name__ += '_' + class_T.__name__  # rename the subclass to reflect its heritage
    return Foo

class Base1:
    def bar(self):
        print('Base1.bar()')

class Base2:
    def bar(self):
        print('Base2.bar()')

Foo_Base1 = template(Base1)
print('Foo_Base1 base classes: {}'.format(Foo_Base1.__bases__))

Foo_Base2 = template(Base2)
print('Foo_Base2 base classes: {}'.format(Foo_Base2.__bases__))

subclass1 = Foo_Base1()
subclass1.fun()
subclass1.bar()
subclass2 = Foo_Base2()
subclass2.fun()
subclass2.bar()

Output:

Foo_Base1 base classes: (<class __main__.Base1 at 0x00A79C38>,)
Foo_Base2 base classes: (<class __main__.Base2 at 0x00A79DC0>,)
Foo_Base1.fun()
Base1.bar()
Foo_Base2.fun()
Base2.bar()

The code in the (unimaginatively-named) template() function is an example of what is commonly called a class factory or an implementation of the Factory pattern. So, incidentally, you might find my answer to the question What exactly is a Class Factory? informative.

Edit: Added code to create different class names for each subclass returned—which was inspired by @aaronasterling's insight (in a now deleted comment) about potential confusion when debugging if the class manufactured always has the same name.




回答2:


This is meaningless in Python, since it does not have templates. My understanding of parameterized templates in C++ (which is rather vague, since it is many years since I have looked at them), is that it acts like a class factory, and can create a subclass of whatever class you give it that has additional methods or attributes added.

In Python you can do this with a factory function that takes a class and returns a new class at runtime:

In [1]: def subclassFactory(cls):
   ...:     class Foo(cls):
   ...:         def fun(self):
   ...:             return "this is fun"
   ...:     return Foo
   ...: 

In [2]: class A(object):
   ...:     pass
   ...: 

In [5]: C = subclassFactory(A)

In [6]: C
Out[6]: <class '__main__.Foo'>
In [7]: c = C()
In [9]: c.fun()
Out[9]: 'this is fun'
In [10]: isinstance(c, A)
Out[10]: True


来源:https://stackoverflow.com/questions/3876921/metaclass-to-parametrize-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!