Как я объяснил в моем комментарии, проблема возникает, когда вы назначаете от 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
, а не сам класса. Они могут быть вынуждены работать с самим классом, создавая метакласс - который является классом класса - для вашего класса; это считается «глубокой черной магией» многих людей, и я не рекомендую идти этим путем, если вы можете избежать этого.
Я считаю, что приведенный ниже пример, вероятно, самый простой способ реализовать поведение, которое вы хотите. Такой подход оставляет использование свойств в пользу непосредственно переопределение атрибутов методы получения и установки:
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% уверенным, что мои переопределения, как указано выше, не приведут к какой-либо другой проблеме для вас. Я считаю, что они звучат, но просто имейте в виду, что эти конкретные уголки питона могут быть довольно сложными.
Когда вы назначаете 5 'i' посредством' GetPartition.i = 5', вы ** переписываете свойство ** и * обходя * свойство setter. Свойство больше не существует в этой точке. Вы можете подтвердить это, выполнив 'GetPartition.i = 5',' gp = GetPartition() ',' gp.i = 2', 'print (gp.i, GetPartition.i)'. Геттер свойств и сеттер работают только с экземплярами «GetPartition», а не с самим классом. Если вы хотите обновить «статическую переменную» (имея в виду, что у Python * фактически нет статических переменных *), вам нужно будет сделать «GetPartition._i = 5», как в вашем примере кода. –
@RickTeachey Вначале thx для вашего ответа, тогда я попытался установить его так, как 'GetPartition._i = 5', но я столкнулся с аналогичными проблемами при попытке получить его, какие-нибудь идеи, как получить его из другого класса? –
Ну, простой способ получить его из другого места - это сделать 'print (GetPartition._i)' вместо 'print (GetPartition.i)'. Я понимаю, что это не оптимально. Есть и другие способы выполнить то, что вы хотите, но все те, о которых я знаю, довольно сложны. –