LINUX.ORG.RU

Python создание объектов и запихивание их в list

 


0

1

Здравствуйте, коллеги!

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

class obj:
  __value = []
  def __init__(self, string: str):
    self.__value.append(string)

  def clean(self):
    self.__value = []

if __name__ == '__main__':
  lst = []
  for i in range 5:
    objct = obj('python')
    #lst.append(objct)

Данный код я не проверял, но в схожей ситуации у меня при создании нового объекта __value имел данные из ранее созданного объекта. И размерность __value начинала расти. Сначала len(__value) = 1, потом 2, далее 3 и т.д..

Возможно я не правильно понимаю механизм уничтожения объектов (сборщик мусора), но объект должен уничтожаться когда на его экземпляр перестает указывать последняя переменная (Счетчик указателей становится равным нулю)?

Соответственно, предыдущий экземпляр ‘objct’ должен удалятся в момент: objct = obj(‘python’) и, соответственно чистится память, но этого не происходит.

Видимо я что-то не правильно понимаю? Победить эту беду мне удалось добавив в конструктор self.__value = []. Но но осадочек остался…

Теперь подходим к засовыванию объектов в list (массив).

Я специально привел функцию ‘clean(self)’

В массив попадает лишь указатель на экземпляр класса, а не сам класс. Можно ли как-то заставить python запихивать в массив не указатель, а весь экземпляр (объект) целиком?


Это описывается подробно в документации, которая идёт вместе с Python.

При таком объявлении, __value является атрибутом класса, а не экземпляра.

Атрибуты экземпляра необходимо определять в __init__.

Соответственно, предыдущий экземпляр ‘objct’ должен удалятся в момент: objct = obj(‘python’) и, соответственно чистится память, но этого не происходит

Это вредное предположение. Python не специфицирует, как работает сборщик мусора. В CPython используется подсчёт ссылок, поэтому будет работать именно так (за исключением того, что на __value остаётся ссылка из класса, поэтому он не будет удалён), но никто не гарантирует, что так будет в будущих версиях CPython, тем более, каком-нибудь PyPy или IronPython.

emorozov
()

В массив попадает лишь указатель на экземпляр класса, а не сам класс. Можно ли как-то заставить python запихивать в массив не указатель, а весь экземпляр (объект) целиком?

Нет.

Если это действительно нужно, то надо использовать методы .copy() и/или модуль deepcopy.

emorozov
()
Ответ на: комментарий от AntonI

У Вас __value статический член класса (один на все экземпляры).

Опс…

Можно поподробнее?

Я видимо упустил некоторые нюансы. С/С++ я все таки знаю больше, просто писать на С дольше.

Почему __value оказался статическим? Из-за объявления в теле класса?

А как объявлять обычные (не статические) переменные, которые доступны всем методам класса, но только в пределах текущего экземпляра?

В теле функции (конструктора) типа self.value2 = []?

HighMan
() автор топика
Ответ на: комментарий от emorozov

Если это действительно нужно, то надо использовать методы .copy() и/или модуль deepcopy.

Понял. Спасибо.

Получается, что list это нечто вроде массива указателей, типа void ** lists.

HighMan
() автор топика
Ответ на: комментарий от HighMan

С/С++ я все таки знаю больше

Многие знания, многие печали. Воспринимайте list как коллекцию, не вдаваясь в подробности реализации, добиваясь иммутабельности парадигмами.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 2)
Ответ на: комментарий от HighMan

Почему __value оказался статическим? Из-за объявления в теле класса?

Да

А как объявлять обычные (не статические) переменные, которые доступны всем методам класса, но только в пределах текущего экземпляра?

В теле функции (конструктора) типа self.value2 = []?

Да:-)

Рекомендую нагуглить статью «10 ловушек питон»

AntonI ★★★★
()
Ответ на: комментарий от AntonI

В любом месте где есть self, не обязательно в ините. Хоть снаружи класса.

Не понял про «снаружи класса»?

Как self может быть за пределами класса?

Или вы имеете в виду реализацию методов класса вне его тела?

Кстати, как правильно расписывать методы класса, например, в другом файле?

Типа как в С++, объявление класса в заголовочном файле, а реализация методов в срр файле.

HighMan
() автор топика
Ответ на: комментарий от AntonI

Рекомендую нагуглить статью «10 ловушек питон»

Спасибо. Поищу.

Подводные камни - это же замечательно!

Подводные мины хуже, а именно ими насыщены языки программирования.

HighMan
() автор топика
Ответ на: комментарий от HighMan

Не понял про «снаружи класса»?

class A: pass
a = A()
a.x = 1  # <== здесь self это a

Или вы имеете в виду реализацию методов класса вне его тела?

так тоже можно

class A: pass
a = A()
A.f = lambda self: 1
a.f()

это же питон…

AntonI ★★★★
()

Можно ли как-то заставить python запихивать в массив не указатель, а весь экземпляр (объект) целиком?

Все что есть в питоне это указатели на объекты. Любое присваивание это работа с указателем на объект. Про сборку мусора думать пока не надо, это же питон - он сам об этом думает.

AntonI ★★★★
()
>>> class Foo:
...     for i in range(10):
...         print(i)
... 
0
1
2
3
4
5
6
7
8
9

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

class Foo:
  x = 42
  def __init__(self, x: int | None = None):
    self.x = x or self.x

а всякие списки - это изменяемые типы данных, те ты их модицировать можешь, поэтому оно всегда внутри инита должно инициализироваться

uwuwuu
()
Последнее исправление: uwuwuu (всего исправлений: 1)
Ответ на: комментарий от uwuwuu

Ну насчёт range вы меня совсем за лоха принимаете.

Я им изредка пользуюсь, когда удобнее перебрать лист по индексу.

А то, что вы сотворили в конструкторе класса - говнокод.

Нужно всерьез задумываться что и для чего вы делаете.

Ну ладно. Погорячился. Может не говнокод, но я так не пишу.

Код должен быть сразу понятным для человека, который даже не хочет разбираться в чужом творчестве.

HighMan
() автор топика
Ответ на: комментарий от HighMan

что ты не пишешь? я показываю, что в питоне так можно. и много чего можно, что не следует делать… Прежде чем начинать, наверное, подрочиться с основами, почитать букварь где рассказано как C реализовать объекты… Но это сложно. Вот что точно посоветую НЕ ПИСАТЬ НИКОГДА В JAVA-СТИЛЕ на сабже. Я когда вижу все эти DDD просто хочется взять соевое чудище, начитавшееся Мартина начать бить головой об стол. Это так же как говорить на русском по правилам английского окружающие тебя поймут, но если ты не иностранец, то станут считать тебя психически-больным и избегать общения с тобой

uwuwuu
()
Ответ на: комментарий от uwuwuu

Вот что точно посоветую НЕ ПИСАТЬ НИКОГДА В JAVA-СТИЛЕ на сабже.

Что значит Java стиль?

Я совсем чуть-чуть знаю JS. С Java не знаком совсем и, даже, не горю желанием знакомиться. Что-то в нем есть эдакое… Что меня отталкивает.

Наверное, имеет место админский опыт по сопровождению Java проектов. Это, по крайней мере у меня, всегда боль.

HighMan
() автор топика

Питон построен как набор вложенных пространств имён с шоркатами между ними

по факту и module (import … ) и def и class - синонимы с оттенками смыслов

они создают кодовый объект который при вызове делает что то

чисто сравни def и class

исполнение def создаёт вызываемый объект со своим пространством имён вызов которого и есть выполнение функции на данных аргументах

исполнение class cоздаёт объект class вызов которого с данными аргументами производит обращение к init уже в контексте пространства имён этого class - соответственно __values - оно у класса а не у объекта( у которого self.__values)

всё просто кста

и кста как показали примером цикла в теле объявления класса - это очень хороший пример как ваще прикрученно создание чего угодно в Python - когда объявляется class происходит его исполнение (всего что под class X():) весь код в числе которого обычно набор def команд когда исполняется def - происходит создание callable - и привязывание к имени у этого класса

qulinxao3
()
Последнее исправление: qulinxao3 (всего исправлений: 1)