python metaclass不记得新值

时间:2011-08-29 10:03:32

标签: python metaclass

我写了一个带有元类法术的Person。在元类中,我更改了一个属性并且没有问题,但是如果我想将这个新值用于另一个操作,则它不起作用并使用前一个值。 我该如何解决这个问题?

class Spell(type):
    def __new__(cls,classname,super,classdict):
        def pph( hours ): return lambda self : classdict['pay_per_hour'] * hours

        classdict['pay_per_hour'] = 12
        classdict['day_salary'] = pph(8)
    return type.__new__(cls, classname, super, classdict )

class Person(metaclass=Spell):
    def __init__(self,name,lastname,bday):
        self.name = name
        self.lastname = lastname
        self.bday = bday

    def get_name(self):
        return self._name
    def get_lastname(self):
        return self._lastname
    def get_bday(self):
        return self._bday
    def __repr__(self):
        return "name: {0}, lastname: {1}, bday: {2}".format(self.name,self.lastname,self.bday)

if __name__ == "__main__":
    persona4 = Person("lugdfgca","djfosd","16 febbraio 85")
    print(persona4.pay_per_hour)
    print(persona4.day_salary())
    persona4.pay_per_hour=15
    print(persona4.pay_per_hour)
    print(persona4.day_salary())

输出

12
96
15
96

但96是12 * 8而不是15 * 8,为什么?错误在哪里?

2 个答案:

答案 0 :(得分:2)

您创建的lambda引用在类构造期间填充的字典。稍后(在类创建之后)对类变量的更改不会反映在其中,但即使是这种情况,行persona4.pay_per_hour = 15也会分配新的实例属性,而不是更改类属性。在self.pay_per_hour生成的函数中使用pph来获取有问题的实例此时使用的值。

或者,更好的是,取消元类。这里没有理由使用它们,正如你所看到的那样,很容易使事情变得不那么可扩展。

class Spell:
    pay_per_hour = 12
    hours_per_day = 8

    # @property # allows nicer syntax, look it up if you don't know it
    def day_salary(self):
        return hours_per_day * pay_per_hour

class Person(Spell):
    ...

这会在实例级别透明地处理pay_per_hour和hours_per_day的更改。

答案 1 :(得分:1)

问题是你的函数pph只在类字典中查找pay_per_hour的值,而你只覆盖实例中pay_per_hour的值。在Python中,当您查找对象字段的值时,它首先检查实例字典,然后检查类字典(以及mro顺序中的所有超类)。

您需要将您的元类更改为:

def __new__(cls,classname,super,classdict):
    def pph( hours ): return lambda self : self.pay_per_hour * hours

    classdict['pay_per_hour'] = 12
    classdict['day_salary'] = pph(8)