2015-03-29 4 views
0

Я пытаюсь создать статическую переменную, к которой можно получить доступ через разные классы, присвоить ей значение и получить это значение, когда это необходимо. Я использовать this way для того, чтобы достичь этого, и это приводит меня в том числе собственности, как следующее:Получить статическое значение переменной

class GetPartition(Partition): 
    _i = 100 
    def __init__(self): 
     super(Partition,self).__init__("get") 
    def get_i(self): 
     return type(self)._i 
    def set_i(self,val): 
     type(self)._i = val 
    i = property(get_i, set_i) 

и это класс Partition при необходимости:

class Partition(BaseCommand): 
    def __init__(self,type): 
     super(Partition,self).__init__("databaseTest") 
     self.type = type 

Таким образом, при присвоении значения i из другого класса, я назначая его непосредственно, как:

GetPartition.i = 5 

и среди этого класса при печати GetPartition.i это дает мне 5, но при попытке получить это значение из другого класса:

partitionNum = GetPartition() 
print(partitionNum.i) # 100 
print(partitionNum.get_i()) # 100 
print(GetPartition.i) # <property object at 0x12A938D0> 
print(GetPartition._i) # 100 
+1

Когда вы назначаете 5 'i' посредством' GetPartition.i = 5', вы ** переписываете свойство ** и * обходя * свойство setter. Свойство больше не существует в этой точке. Вы можете подтвердить это, выполнив 'GetPartition.i = 5',' gp = GetPartition() ',' gp.i = 2', 'print (gp.i, GetPartition.i)'. Геттер свойств и сеттер работают только с экземплярами «GetPartition», а не с самим классом. Если вы хотите обновить «статическую переменную» (имея в виду, что у Python * фактически нет статических переменных *), вам нужно будет сделать «GetPartition._i = 5», как в вашем примере кода. –

+0

@RickTeachey Вначале thx для вашего ответа, тогда я попытался установить его так, как 'GetPartition._i = 5', но я столкнулся с аналогичными проблемами при попытке получить его, какие-нибудь идеи, как получить его из другого класса? –

+0

Ну, простой способ получить его из другого места - это сделать 'print (GetPartition._i)' вместо 'print (GetPartition.i)'. Я понимаю, что это не оптимально. Есть и другие способы выполнить то, что вы хотите, но все те, о которых я знаю, довольно сложны. –

ответ

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, а не сам класса. Они могут быть вынуждены работать с самим классом, создавая метакласс - который является классом класса - для вашего класса; это считается «глубокой черной магией» многих людей, и я не рекомендую идти этим путем, если вы можете избежать этого.

Я считаю, что приведенный ниже пример, вероятно, самый простой способ реализовать поведение, которое вы хотите. Такой подход оставляет использование свойств в пользу непосредственно переопределение атрибутов методы получения и установки:

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% уверенным, что мои переопределения, как указано выше, не приведут к какой-либо другой проблеме для вас. Я считаю, что они звучат, но просто имейте в виду, что эти конкретные уголки питона могут быть довольно сложными.

+0

Спасибо за эту замечательную иллюстрацию, на самом деле я пробовал этот путь, но не могу управлять им, это дает мне 'super() принимает как минимум 1 аргумент (0 задано)' в строке 'super() .__ setattr __ (attr, value) 'при попытке установить значение' ei = 5'. и предоставление его «я» не работает, так как требует определенного типа. –

+0

Также стоит упомянуть, что я не получу значение из того же класса, но из другого с разным расположением –