2012-06-21 162 views
2

我想在类的创建过程中自动运行在任何派生类的基类中定义的类方法。例如:Python派生类在派生类上自动运行类方法

class Base(object): 
    @classmethod 
    def runme(): 
    print "I am being run" 

    def __metclass__(cls,parents,attributes): 
    clsObj = type(cls,parents,attributes) 
    clsObj.runme() 
    return clsObj 


class Derived(Base): 
    pass: 

这里发生的是,当创建Base时,'runme()'将会触发。但是,创建派生时没有任何反应。

问题是:如何在创建派生的时使'runme()'也被触发。

这是我至今想:如果我明确设置派生元类基地的,它会工作。但我不希望发生这种情况。我基本上想要派生的使用基地的元类没有我必须明确地设置它。

+0

你为什么定义为'喜欢这个类里面__metaclass__'?它应该被用来将元类设置为一个外部定义的类。 – BrenBarn

+0

@BrenBarn:但为什么它不能像我用过的那样使用它。据我所见,__metaclass__属性是指向一个类对象还是一个函数对象应该不重要。但它确实很重要,我认为你是对的。我想知道为什么?如果可以,请提供一些简单的代码示例。 –

回答

2

参见this answer。基本上,在调用type(cls,parents,attributes)时,您正在创建一个类而不传递关于该类的元类的信息。因此,返回的类没有您想要的元类;相反,它具有元类type。 (具有讽刺意味的是,通过定义__metaclass__这样做,你明确地导致你的类不是而是拥有那个元类。)不需要直接调用类型,你需要调用type.__new__(meta, cls, parents, attrs),其中meta是元类。

但是,在内联定义__metaclass__时无法实现此目的。从您的__metaclass__方法中,您无法引用该方法,因为它是尚未定义的类的方法。你想做点像

def __metaclass__(cls, bases, attrs): 
    type.__new__(metaclassGoesHere, cls, bases, attrs) 

。 。 。但是没有什么东西可以放在metaclassGoesHere中,使它做正确的事情,因为你试图引用的是你试图引用它的方法。

所以只需从外部定义你的元类。

+0

谢谢@BrenBarn。你已经非常清楚这件事了。基本上,需要使用__new__来控制元类对象的实际创建,我们可以控制它并设置该对象的元类。谢谢。 –

0

重命名您的__init__()方法runme()__init__(self)切勿覆盖,它会被调用每次你做Derived

class Base(object): 
    def __init__(self): 
     print "I am being run" 

class Derived(Base): 
    pass 

dummy_instance = Derived() 

复制的实例,并粘贴到时候,它将打印I am being run

+0

是的,我知道这将发生派生实例。但我不是在谈论派生实例,我在谈论派生类。 __init__函数初始化实例属性,但我希望初始化发生在类级别上。这是为我设计的API,所以我真的需要一些元类魔术,但我不明白为什么它不被继承... –

+0

你能提供这个pls的用例@BarrySteyn –

+0

@JonClements I我正在使用SQLalchemy来创建一个ORM。一种做事的模式是使用所谓的声明性反射模式,但是这需要调用基类的类方法。一旦加载类,我希望自动调用此方法。 –

0

试试这个,

class MyMetaclass(type): 

    def __new__(cls, name, bases, dct): 

     runme() 

     return super(MyMetaclass, cls).__new__(cls, name, bases, uppercase_attr) 
0

如果你想要做的事创建类时,你必须做在__metaclass____init__方法。

class foo(object): 
    @classmethod 
    def method(cls): 
     print 'I am being run by', cls.__name__ 

    class __metaclass__(type): 
     def __init__(self, *args, **kwargs): 
      type.__init__(self, *args, **kwargs) 
      self.method() 

class bar(foo): pass 

它打印:

I am being run by foo 
I am being run by bar