2014-07-01 18 views
2

正如标题所示。看起来不管我做什么,__getattr__都不会被调用。我也尝试过(荒谬的,我知道),可预测的没有回应。好像__getattr__在元类中被禁止。元类的__getattr__未被调用

我很感激任何指向文档的指针。

代码:

class PreinsertMeta(type): 

    def resolvedField(self): 
     if isinstance(self.field, basestring): 
      tbl, fld = self.field.split(".") 
      self.field = (tbl, fld) 
     return self.field 

    Field = property(resolvedField) 

    def __getattr__(self, attrname): 
     if attrname == "field": 
      if isinstance(self.field, basestring): 
       tbl, fld = self.field.split(".") 
       self.field = (tbl, fld) 
      return self.field 
     else: 
      return super(PreinsertMeta, self).__getattr__(attrname) 

    def __setattr__(self, attrname, value): 
     super(PreinsertMeta, self).__setattr__(attrname, value) 


class Test(object): 
    __metaclass__ = PreinsertMeta 
    field = "test.field" 

print Test.field # Should already print the tuple 
Test.field = "another.field" # __setattr__ gets called nicely 
print Test.field # Again with the string? 
print Test.Field # note the capital 'F', this actually calls resolvedField() and prints the tuple 

感谢BrenBarn,这里的最后工作实现:

class PreinsertMeta(type): 

    def __getattribute__(self, attrname): 
     if attrname == "field" and isinstance(object.__getattribute__(self, attrname), basestring): 
      tbl, fld = object.__getattribute__(self, attrname).split(".") 
      self.field = (tbl, fld) 
     return object.__getattribute__(self, attrname) 

回答

4

由于documented__getattr__仅如果属性不存在所谓的。由于你的课程具有field属性,因此阻止__getattr__。如果你真的想拦截所有的属性访问,你可以使用__getattribute__,虽然从你的例子中不清楚为什么你需要这样做。请注意,这与元类无关;如果你创建了一个普通类的实例并给它一些属性,你会看到相同的行为。

即使假设你使用了__getattribute__,所以它在属性存在时被调用,你的实现没有多大意义。在__getattr__内部,您尝试获得self.field的值。但是,如果首先调用__getattribute__,则会再次调用该访问权限,从而创建无限递归:为了获得self.field,它必须调用__getattribute__,它再次尝试获得self.field,这又会调用__getattribute__等。有关如何解决此问题,请参阅documentation__getattribute__

+0

谢谢,忘了'__getattribute__'以及:)关于它的一切意义:上面的实现是针对父类的子类,其中'field'成员不能直接引用基类成员,因为它没有'当时存在。 __getattribute__版本允许我在使用时使用已解析的成员变量。既然封闭和子类都没有实例化,我尝试用meta类来实现。 – velis