未调用元类的 __getattr__

vel*_*lis 3 python python-2.7

正如标题所说。看来不管我做什么,__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
Run Code Online (Sandbox Code Playgroud)

感谢 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)
Run Code Online (Sandbox Code Playgroud)

Bre*_*arn 5

文档所述__getattr__仅当属性不存在时才调用。由于您的班级有一个field属性,因此会阻止__getattr__. __getattribute__如果您真的想拦截所有属性访问,则可以使用,尽管从您的示例中不清楚为什么需要这样做。请注意,这与元类无关;如果您创建一个普通类的实例并赋予它一些属性,您会看到相同的行为。

即使假设您使用__getattribute__, 所以它在属性存在时被调用,您的实现也没有多大意义。在内部,__getattr__您尝试获取 的值self.field。但是,如果__getattribute__在第一个地方被调用,它将会再次调用此访问,创建无限递归:为了得到self.field,它具有通话__getattribute__,再次试图获取self.field,而这又要求__getattribute__等见文档__getattribute__对如何解决这个问题。