Как исправить переменные / константы класса при перезаписи словарей? - PullRequest
0 голосов
/ 20 декабря 2018

Я новичок в python и пытаюсь использовать значения по умолчанию и настроить их для экземпляра класса.

Таким образом, в этом примере я определяю переменные DEFAULT_STRING и DEFAULT_SETTINGS, которые можно настроить с помощью customize(), и их следует сбросить на значение по умолчанию reset().

Это нормально работает для DEFAULT_STRING.Но почему-то customize() перекрывает словарь DEFAULT_SETTINGS.

class TestClass:
  DEFAULT_STRING = 'default string'

  DEFAULT_SETTINGS = {
    'key1': 'value1',
    'key2': 'value2'
  }

  def __init__(self):
    self.reset()

  def customize(self):
    self.string = 'custom string'
    self.settings['key2'] = 'CUSTOM VALUE'

  def reset(self):
    self.string = TestClass.DEFAULT_STRING
    self.settings = TestClass.DEFAULT_SETTINGS

test = TestClass()
test.customize()

print(test.DEFAULT_STRING) # default string
print(test.string) # custom string 
print(test.DEFAULT_SETTINGS) # {'key1': 'value1', 'key2': 'CUSTOM VALUE'} 
print(test.settings) # {'key1': 'value1', 'key2': 'CUSTOM VALUE'} 

test.reset()

print(test.DEFAULT_STRING) # default string
print(test.string) # default string 
print(test.DEFAULT_SETTINGS) # {'key1': 'value1', 'key2': 'CUSTOM VALUE'} 
print(test.settings) # {'key1': 'value1', 'key2': 'CUSTOM VALUE'} 

Я почти уверен, что есть очень простое решение, но каким-то образом я застрял между строк ...

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 20 декабря 2018

Вам необходимо понять, что делает

self.settings = TestClass.DEFAULT_SETTINGS

.

Оператор делает settings именем в пространстве имен экземпляра.И он указывает на тот же объект, на который указывает имя DEFAULT_SETTINGS в пространстве имен класса.

Это означает, что оператор не создает новый объект.

Примечание: этобывает и для self.string.Но в этом случае self.string является строкой, которая является неизменной.Это означает, что когда вы назначаете новое значение тому же имени, создается новый объект.

Давайте рассмотрим пример:

>>> class C:
...  S = 'asdasd'
... 
>>> o = C()
>>> o.s = C.S
>>> o.s
'asdasd'
>>> o.s is C.S
True
>>> o.s = 'pasdpdspa'
>>> o.s is C.S
False
>>> o.s = C.S
>>> C.S = 'popopo'
>>> o.s
'asdasd'

С другой стороны, словарь является изменяемыми модифицируется на месте.

Итак, как предлагается в комментариях, чтобы заставить его работать, вам необходимо скопировать такой словарь, например, с

self.settings = dict(TestClass.DEFAULT_SETTINGS))

или еще лучше с

from copy import deepcopy
self.settings = deepcopy(self.DEFAULT_SETTINGS)

Примечание: последнее необходимо, если словарь вложен.dict делает только поверхностную копию, поэтому она не будет работать во всех случаях.

Покажем это на примере:

>>> d = {1:10, 2: {21: 'abc', 22: 'def'}}
>>> d
{1: 10, 2: {21: 'abc', 22: 'def'}}
>>> d2 = dict(d)
>>> d is d2
False
>>> d[2] is d2[2]
True
>>> d2[2] = 99
>>> d
{1: 10, 2: {21: 'abc', 22: 'def'}}
>>> d2 = dict(d)
>>> d2[2][21] = 99
>>> d
{1: 10, 2: {21: 99, 22: 'def'}}

, тогда как

>>> d = {1:10, 2: {21: 'abc', 22: 'def'}}
>>> d2 = deepcopy(d)
>>> d2[2] is d[2]
False
>>> d2[2][21] = 99
>>> d
{1: 10, 2: {21: 'abc', 22: 'def'}}

Примечание 2: как вы можете заметить, имя DEFAULT_SETTINGS в пространстве имен класса может быть достигнуто через экземпляр, то есть

self.DEFAULT_SETTINGS

вместо

TestClass.DEFAULT_SETTINGS

Я предлагаю провести небольшое исследованиеНеизменяемые и изменчивые типы Python, модификация на месте, пространства имен и разрешение имен, наследование и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...