Составное присвоение на переменные класса Python и переменные экземпляра

Я пытался понять обработку Python переменных класса и переменных экземпляра. В частности, я нашел этот ответ довольно полезным. В основном это говорит, что, если Вы объявляете переменную класса и затем Вы делаете уроки к [instance].property, Вы будете присваивать другой переменной в целом - один в другом пространстве имен от переменной класса.

Таким образом я рассмотрел - если я хочу, чтобы каждый экземпляр моего класса имел участника с некоторым значением по умолчанию (скажите, что нуль), должен я делать это как это:

class Foo:
    num = 0

или как это?

class Foo:
    def __init__(self):
        self.num = 0

На основе того, что я считал ранее, я буду думать, что второй пример инициализировал бы 'правильную' переменную (экземпляр вместо переменной класса). Однако я нахожу, что первый метод работает отлично также:

class Foo:
    num = 0

bar = Foo()
bar.num += 1 # good, no error here, meaning that bar has an attribute 'num'
bar.num
>>> 1
Foo.num
>>> 0 # yet the class variable is not modified! so what 'num' did I add to just now?

Так.. почему это работает? Что я не получаю? FWIW, мое предшествующее понимание ООП прибыло из C++, таким образом, объяснение по аналогии (или указывающий, где это ломается) могло бы быть полезным.

5
задан Community 23 May 2017 в 12:16
поделиться

4 ответа

Лично я нашел эти документы Шалаба Чатурведи чрезвычайно полезными и информативными по этому вопросу.

bar.num + = 1 - это сокращение для bar.num = bar.num + 1 . Это выбирает переменную класса Foo.num с правой стороны и присваивает ее переменной экземпляра bar.num .

5
ответ дан 15 December 2019 в 00:58
поделиться

В следующем коде num является членом класса.

class Foo:
    num = 0

Эквивалент C ++ будет выглядеть примерно так:

struct Foo {
  static int num;
};

int Foo::num = 1;

class Foo:
    def __init__(self):
        self.num = 0

self.num - член экземпляра ( self - экземпляр Foo ).

В C ++ это будет что-то вроде

struct Foo {
  int num;
};

. Я считаю, что Python позволяет вам иметь член класса и член экземпляра с одинаковыми именами (C ++ этого не делает). Итак, когда вы выполняете bar = Foo () , bar является экземпляром Foo , поэтому с bar.num + = 1 , вы увеличиваете член экземпляра.

2
ответ дан 15 December 2019 в 00:58
поделиться
bar.num += 1

создает новую переменную экземпляра 'num' в экземпляре 'bar', поскольку она еще не существует (и затем добавляет 1 к этому значению)

пример:

class Foo:
  def __init__(self):
    self.num= 1

bar = Foo()
print bar.num

это печатает 1

print bar.foo

это дает ожидаемую ошибку: Traceback (последний вызов последним): File "", строка 1, в AttributeError: Foo instance не имеет атрибута 'foo'

bar.foo = 5
print bar.foo

, теперь это печатает 5

, поэтому, что происходит в вашем примере: bar.num разрешается как Foo.num, потому что есть только атрибут класса. тогда фактически создается foo.num, потому что вы присваиваете ему значение.

0
ответ дан 15 December 2019 в 00:58
поделиться

Я думаю, вы только что нашли там ошибку в Python. bar.num + = 1 должен быть ошибкой, вместо этого он создает атрибут num на панели объектов, отличный от Foo.num.

Это действительно странное поведение.

-3
ответ дан 15 December 2019 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: