Ответ 1
Как я объяснил в своем комментарии, проблема возникает, когда вы назначаете от 5 до i
посредством:
GetPartition.i = 5
С помощью этой строки кода вы перезаписываете свойство и "обходите" свойство setter. Я имею в виду: setter не называется, когда вы вызываете его имя атрибута из класса; он вызывается только при вызове его имени атрибута из экземпляра класса.
Так как он был перезаписан, свойство больше не существует в этой точке, и все ссылки на атрибут i
, будь то из экземпляров класса или из самого класса, различны. Они больше не будут извлекать один и тот же объект, кроме отдельных объектов.
Вы можете подтвердить эту проблему, выполнив следующие действия:
gp = GetPartition()
print(GetPartition.i) # the property is returned
GetPartition.i = 5 # here the property is overwritten
print(GetPartition.i) # 5 ; the property is gone
print(gp.i) # 5 because gp instance doesn't have its own i
gp.i = 2 # now gp does have its own i
print(gp.i) # 2
print(GetPartition.i) # 5 ; i is not synced
Как я сказал выше, геттеры и сеттеры property
(и дескрипторы в целом) работают только с экземплярами GetPartition
, а не с самим классом. Их можно заставить работать с самим классом, создав метакласс - класс класса - для вашего класса; это считается "глубокой черной магией" многих людей, и я не рекомендую идти этим путем, если вы можете избежать этого.
Я считаю, что приведенный ниже пример, вероятно, самый простой способ реализовать поведение, которое вы хотите. Этот подход отказывается от использования свойств в пользу переопределения методов getter и setter напрямую:
class Example():
i = 1 # this is a "static variable"
j = 3 # this is a regular class attribute
#designate which of the class attributes are "static"
statics = {'i'}
def __getattribute__(self, attr):
'''Overrides default attribute retrieval behavior.'''
if attr in Example.statics:
#use class version if attr is a static var
return getattr(Example, attr)
else:
#default behavior if attr is not static var
return super().__getattribute__(attr)
def __setattr__(self, attr, value):
'''Overrides default attribute setting behavior.'''
if attr in Example.statics:
#use class version if attr is a static var
setattr(Example, attr, value)
else:
#default behavior if attr is not static var
super().__setattr__(attr, value)
#testing
if __name__ == '__main__':
print("\n\nBEGIN TESTING\n\n")
e = Example()
#confirm instance and class versions of i are the same
test = "assert e.i is Example.i"
exec(test)
print(test)
e.i = 5
#confirm they remain the same after instance change
test = "assert e.i is Example.i"
exec(test)
print(test)
Example.i = 100
#confirm they remain the same after class change
test = "assert e.i is Example.i"
exec(test)
print(test)
e.j = 12
#confirm both versions of j are distinct
test = "assert e.j is not Example.j"
exec(test)
print(test)
print("\n\nTESTING COMPLETE\n\n")
Если вы не знакомы с __getattribute__
и __setattr__
, я должен сообщить вам, что переопределение их часто довольно опасно и может вызвать большие проблемы (особенно __getattribute__
). Вы обнаружите, что многие просто говорят: "Не делайте этого, переосмыслите свою проблему и найдите другое решение". Правильное выполнение переопределений требует глубокого понимания широкого круга вопросов python.
Я не утверждаю, что имею такое глубокое понимание (хотя я думаю, что у меня довольно хорошее понимание), поэтому я не могу быть на 100% уверенным, что мои переопределения, как указано выше, не приведут к какой-либо другой проблеме для вас. Я считаю, что они звучат, но просто имейте в виду, что эти конкретные уголки питона могут быть довольно сложными.