【问题标题】:Metaclass to parametrize Inheritance用于参数化继承的元类
【发布时间】:2011-04-22 01:45:05
【问题描述】:

我已经阅读了一些关于 Python 元类的教程。我以前从未使用过,但我需要一个相对简单的东西,而且所有教程似乎都针对更复杂的用例。我基本上想创建一个模板类,它具有一些预先指定的主体,但将其基类作为参数。因为我是从 C++/D 模板中得到这个想法的,所以这里有一个我想要编写的代码在 C++ 中的示例:

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

【问题讨论】:

    标签: c++ python templates metaprogramming metaclass


    【解决方案1】:

    虽然它当然可以用元类来完成,但你可以在没有它们的情况下做你想做的事,因为在 Python 中,类本身就是对象。这意味着——令人惊讶的是——基本上只需要对 C++ 代码进行几乎一对一的翻译。除了因此相对简单之外,它还可以在 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()
    

    输出:

    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()
    

    (名称难以想象)template() 函数中的代码是通常称为class factory 的示例或工厂模式的实现。因此,顺便说一句,您可能会发现 my answer 对问题 What exactly is a Class Factory? 提供了丰富的信息。

    编辑:添加了代码来为每个返回的子类创建不同的类名——这受到@aaronasterling 的洞察力(在现已删除的评论中)关于调试类时潜在混淆的启发制造的总是具有相同的名称。

    【讨论】:

    • 太棒了,我想元类对于如此简单的事情来说太过分了。事后看来,这个解决方案很有意义,因为类型是 Python 中的第一类对象,并且可以在运行时创建类。不过,我想我对动态语言的思维方式还不够满意,无法自己提出来。
    • 模板 C++(一种强类型语言)中的元类。在像 Python 这样的弱类型中,正如您所指出的,类也是对象,通常没有必要去那里 - 但是当您这样做时,您不仅限于模板参数,还可以做一些令人惊奇的事情。
    • Python 是强类型,您不能像在弱类型语言(如 Javascript)中那样在 Python 中添加字符串和整数。顺便说一句,Python 也是动态类型的
    • @Lie Ryan:你说的很对——我使用了错误的术语,并将强/弱与静态/动态类型混淆了。谢谢指正。
    【解决方案2】:

    这在 Python 中毫无意义,因为它没有模板。我对 C++ 中的参数化模板的理解(这是相当模糊的,因为我已经有很多年没有看过它们了),它就像一个类工厂,并且可以创建你给它的任何类的子类,它有额外的方法或添加的属性。

    在 Python 中,您可以使用工厂函数执行此操作,该函数接受一个类并在运行时返回一个新类:

    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
    

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 1970-01-01
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 2018-01-10
      • 1970-01-01
      • 2019-12-14
      • 2016-09-21
      相关资源
      最近更新 更多