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)
精彩评论