Я до сих пор довольно новичок в Python, и мой опыт OO приходит из Java. Поэтому у меня есть код, который я написал на Python, что очень необычно для меня, учитывая следующий код:
class MyClass():
mylist = []
mynum = 0
def __init__(self):
# populate list with some value.
self.mylist.append("Hey!")
# increment mynum.
self.mynum += 1
a = MyClass()
print a.mylist
print a.mynum
b = MyClass()
print b.mylist
print b.mynum
Выполнение этого результата приводит к следующему выводу:
['Hey!']
1
['Hey!', 'Hey!']
1
Ясно, что я ожидал бы, что переменные класса приведут к тем же точным данным и к тому же точному результату... То, что я не могу найти нигде, - это то, что делает список отличным от строки или числа, почему это список, ссылающийся на тот же список из первого экземпляра в последующих? Ясно, что я, вероятно, неправильно понимаю какую-то сферу механики или механику создания списка.
Ответ 1
Ответ tlayton - часть истории, но она не объясняет все.
Добавьте
print MyClass.mynum
чтобы еще больше смутить:). Он напечатает "0". Зачем? Поскольку строка
self.mynum += 1
создает переменную экземпляра и впоследствии увеличивает ее. Он не увеличивает переменную класса.
История mylist отличается.
self.mylist.append("Hey!")
не будет создавать список. Он ожидает, что переменная с функцией "добавить" будет существовать. Поскольку экземпляр не имеет такой переменной, он заканчивает обращение к одному из класса, который существует, поскольку вы его инициализировали. Как и в Java, экземпляр может "неявно" ссылаться на переменную класса. Предупреждение, подобное "полям класса, должно быть указано классом, а не экземпляром" (или что-то в этом роде, прошло некоторое время с тех пор, как я увидел его на Java) было бы в порядке. Добавить строку
print MyClass.mylist
чтобы проверить этот ответ:).
Короче: вы инициализируете переменные класса и обновляете переменные экземпляра. Экземпляры могут ссылаться на переменные класса, но некоторые операторы "обновления" автоматически создадут переменные экземпляра для вас.
Ответ 2
Что вы здесь делаете, это не просто создание переменной класса. В Python переменные, определенные в классе, приводят как к переменной класса ( "MyClass.mylist" ), так и к переменной экземпляра ( "a.mylist" ). Это отдельные переменные, а не только разные имена для одной переменной.
Однако, когда переменная инициализируется таким образом, начальное значение оценивается только один раз и передается каждому переменному экземпляра. Это означает, что в вашем коде переменная mylist каждого экземпляра MyClass относится к одному объекту списка.
Разница между списком и числом в этом случае заключается в том, что, как и в Java, примитивные значения, такие как числа, копируются при передаче из одной переменной в другую. Это приводит к поведению, которое вы видите; даже если инициализация переменных оценивается только один раз, копируется 0, когда она передается каждой переменной экземпляра. Однако, как объект, список не делает этого, поэтому ваши вызовы append() поступают из одного и того же списка. Вместо этого попробуйте:
class MyClass():
def __init__(self):
self.mylist = ["Hey"]
self.mynum = 1
Это приведет к тому, что значение будет оцениваться отдельно каждый раз, когда создается экземпляр. В отличие от Java, вам не нужны объявления класса для сопровождения этого фрагмента; назначения в __init __() служат как все необходимые декларации.
Ответ 3
Я считаю, что разница в том, что +=
- это назначение (точно так же, как =
и +
), а append
изменяет объект на месте.
mylist = []
mynum = 0
Это присваивает некоторые переменные класса один раз, во время определения класса.
self.mylist.append("Hey!")
Это изменяет значение MyClass.mylist
путем добавления строки.
self.mynum += 1
Это то же самое, что и self.mynum = self.mynum + 1
, т.е. присваивает self.mynum
(член экземпляра). Чтение из self.mynum
переходит к члену класса, так как в это время не существует экземпляра этого имени.