Разное поведение для статических атрибутов класса

Почему по разному ведет себя статический атрибут класса в случаи с pandas? Возможно, что я заморачиваюсь конечно, но такое поведение не дает покоя.

class test:
    table=[]
    def __init__(self,count):
        self.a=count

    def changer(self):
        self.a+=1
        self.table=self.table.append(self.a)

class test2:
    table=pd.DataFrame()
    def __init__(self,count):
        self.a=count

    def changer(self):
        self.a+=1
        self.table=self.table.append({self.a:self.a},ignore_index=True)

for i in [1,2,3]:
    i=test(i)
    i.changer()
print(test.table)
    
for i in [5,6,7]:
    i=test2(i)
    i.changer()
print(test2.table)

в первом случаи статический атрибут список. и print(test.table)>>>[2,3,4] во втором случаи объект pandas, в который построчно добавляем строки, но результат пустой dataframe. Чем вызвано такое странное поведение и как лучше это обойти?


Ответы (1 шт):

Автор решения: CrazyElf

Если вы добавите print(self.table) в оба метода changer, то вас будет ожидать некоторый сюрприз. Вдруг выяснится, что self.table после присвоения ей нового значения - это совсем отдельная сущность от class.table и у первого класса в self.table после присваивания будет вообще значение None.

Однако при этом self.table.append в случае списка пополняет class.table, что логично - ведь для списка .append работает in place и добавляет значения именно в тот список, на который указывает ссылка class.table, а вот с Pandas такой трюк не пройдёт, потому что там table.append не добавляет ничего в имеющуюся таблицу, а создаёт новую.

Но я могу вам подсказать вариант, который будет работать в случае с Pandas. Для этого надо поменять инициализацию класса test2 и метод changer:

class test2:
    table=pd.DataFrame({0: [0]}) # делаем одну колонку с одним значением
    def __init__(self,count):
        self.a=count

    def changer(self):
        self.a+=1
        self.table[self.a] = self.a # пишем новое значение в исходный DataFrame

Вывод:

[2, 3, 4]
   0  6  7  8
0  0  6  7  8

Хотя вру, можно даже не менять инициализацию, а сделать такое присвоение в changer:

    def changer(self):
        self.a+=1
        self.table.loc[0, self.a] = self.a

Но результат при этом будет float:

[2, 3, 4]
     6    7    8
0  6.0  7.0  8.0
→ Ссылка