Я написал класс 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, почему? где ошибка?
Лямбда, которую вы создали, относится к словарю, заполненному во время построения класса. Позже (после создания класса) изменения в переменных класса не отражаются в нем, но даже если это было так, строка 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 прозрачно и на уровне экземпляра.
Проблема в том, что ваша функция 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)