开发者

python metaclass doesn't remember the new value

I wrote a class Person with a metaclass Spell. In the metaclass I change an attribute and it is ok, but if i want to use this new value for another operation, it doesn't work and it use the previous value. How can i fix this?

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):
        retu开发者_Python百科rn "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())

The output is

12
96
15
96

but 96 is 12*8 not 15*8, why? where is the error?


The lambda you created refers to the dictionary filled during class construction. Later (after class creation) changes to class variables are not reflected in it, but even if that was the case, the line persona4.pay_per_hour = 15 assigns a new instance attribute instead of changing the class attribute. Use self.pay_per_hour in the functions produced by pph to get the value the instance in question uses at the moment.

Or, even better, do away with the metaclass. There's no reason to use them here, and as you saw, it's easy to make things less extensible than needed.

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):
    ...

This handles changes to pay_per_hour and hours_per_day transparently and at instance level.


The problem is that your function pph only look up the value of pay_per_hour in the class dictionary, while you only override the value of pay_per_hour in the instance. In Python, when you lookup a value of a field of an object, it first check in the instance dictionary, then in the class dictionary (and all the super class in the mro order).

You need to change your metaclass to:

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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜