Почему область видимости Python ведет себя по-разному для переменных списка и строковых переменных? - PullRequest
0 голосов
/ 02 июня 2018

Скажите, что у меня есть следующий код Python:

import sys

class DogStr:
    tricks = ''

    def add_trick(self, trick):
        self.tricks = trick

class DogList:
    tricks = []

    def add_trick(self, trick):
        self.tricks.append(trick)

# Dealing with DogStr
d = DogStr()
e = DogStr()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)

# Dealing with DogList
d = DogList()
e = DogList()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)

При запуске этого кода с Python 3.6.5 я получаю следующий вывод:

trick d
trick e
['trick d', 'trick e']
['trick d', 'trick e']

Разница между DogStr иDogList состоит в том, что я воспринимаю tricks как строку в первом и как список в последнем.

При работе с DogStr трюки ведут себя как переменная экземпляра.НО с трюками DogList ведет себя как переменная класса.

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

Вот мне и интересно.Чем это объясняется?

1 Ответ

0 голосов
/ 02 июня 2018

Разница заключается не в типе объекта, а в том, что ваш код делает с ним.

Существует большая разница между этими двумя:

self.tricks = trick

и:

self.tricks.append(trick)

Первый self.tricks = trick присваивает значение атрибуту tricks из self.

Второй self.tricks.append(trick) возвращает self.tricks и вызывает для него метод (который здесь изменяет свои значения).


Проблема, в вашем случае, заключается в том, что в экземпляре self не определено tricks, поэтому self.tricks.append получает атрибут tricksкласс и изменяет его, но self.tricks = ... создает вместо него новый атрибут self.

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

Как это исправить?

Это неправильно:

def add_trick(self, trick):
    self.tricks = trick

Если tricks является атрибутом класса, add_trick должен быть методом класса:

@classmethod
def add_trick(cls, trick):
    cls.tricks = trick

Если есть причины для add_trick быть методом экземпляра, то просто сделайте это:

def add_trick(self, trick):
    DogStr.tricks = trick
...