元类的 __getattr__ 方法未被调用

4
正如标题所说。无论我做什么,似乎__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)
1个回答

8
文档所述,只有在属性不存在时才会调用__getattr__。由于您的类具有field属性,那么会阻止__getattr__被调用。如果您确实想截获所有属性访问,可以使用__getattribute__,尽管从您的示例中不清楚为什么需要这样做。请注意,这与元类无关; 如果您创建了普通类的实例并给它一些属性,您将看到相同的行为。
即使假设您使用了__getattribute__,因此在属性存在时它会被调用,您的实现也没有多大意义。在__getattr__内部,您尝试获取self.field的值。但是,如果首先调用了__getattribute__,那么对于该访问也将再次调用__getattribute__,从而创建无限递归:为了获取self.field,必须调用__getattribute__,它又尝试获取self.field,再次调用__getattribute__,依此类推。有关如何解决这个问题,请参见__getattribute__文档

谢谢,我忘记了还有__getattribute__ :) 关于以上实现的意义:上述实现是针对父类的子类的,其中field成员不能直接引用基类成员,因为在此时该成员不存在。__getattribute__版本允许我在使用时使用解析后的成员变量。由于封闭类和子类都不会被实例化,因此我试图通过元类来解决这个问题。 - velis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接