Несмотря на то что я знаю обо всем что говорится в видео, действительно было интересно послушать это в интерпретации Алексея, уверен новичкам зайдет. Однозначно, железобетонный лайк.
Соглашусь с @binaryman440, хоть и сам владею питоном, но посмотрел почти все видео этого канала. @t0digital вы тот специалист которого бы хотелось иметь в своей команде. И один и из трех русскоговрящих айти блогеров которых я вообще смотрю.
25 минут видео, чтобы озвучить примерно следующее "В C# существуют две разновидности типов: ссылочные типы и типы значений. В переменных ссылочных типов хранятся ссылки на их данные (объекты), а переменные типа значений содержат свои данные непосредственно. Две переменные ссылочного типа могут ссылаться на один и тот же объект, поэтому операции над одной переменной могут затрагивать объект, на который ссылается другая переменная. При использовании типов значений каждая переменная имеет собственную копию данных, и для операций с одной переменной невозможно повлиять на другую (за исключением inrefслучаев, и out переменных параметров; см. модификатор ref и out). Ну, а в Пайтоне существуют только переменные ссылочного типа, поскольку в Пайтоне всё является объектами".
Спасибо за выпуск. Следующая идея для ролика: Рассказать/показать как работать с утечками в памяти. Думаю, большинству будет полезно как хантиться за memory leaking'ом.
Переменная (программирование) - поименованная, либо адресуемая иным способом область памяти, адрес которой можно использовать для осуществления доступа к данным и изменять значение в ходе выполнения программы. Если давать такое определение, то объект в куче можно назвать переменной, а в коде мы ссылаемся на эту переменную через ссылки (масло масленное). Ролику конечно лайк в любом случае
Добавлю от себя: Переменная - именованная область памяти! Указатель это тип переменной, адрес другого места в памяти с данными. Обычно доступен в двух режимах: можно прочесть адрес, а можно значение по этому адресу (обычно в куче). А ссылка это указатель, т.е. переменная типа указатель, которая в обычном режиме получает значение по хранимому адресу, без доступа к указателю, без арифметики указателей, т.е. только один режим доступа, обычно неотличимый от переменной простого типа (целого). Т.е. ссылка это тоже тип переменной. Поэтому "В Python нет переменных, а есть ссылки" это троллинг, свой сленг, может быть допустимый в пределах небольшой песочницы.
@@AlexDanov есть устоявшаяся терминология в языках программирования. Python же не один язык на планете. Вот вы говорите об указателях и ссылках. В питоне же нет явного разделения - вот переменная, вот указатель, вот ссылка. В C++, скажем, есть - и это все 3 разные понятия. Что из этого является «переменной» в Python?
@@t0digital переменная связывает имя со значением, которое можно менять, а не с коробкой! Значением может быть адрес объекта в памяти. Всё как обычно. В конце концов, Python поверх Си работает, из которого берется терминология. Попытка утверждать, что в пайтоне нет переменных это антипаттерн, как кнопки работы с окном слева в MacOS, в противовес кнопкам справа в Windows. Или переставленные кнопки Ok/Cansel. Чтобы "а нефиг!" между платформами прыгать. Аналогично вдруг в Python пропали переменные. Хотелось бы узнать первоисточник этой "мудрости".
Алексей, ещё не посмотрел видео, но уже знаю, что будет годнота. Большое спасибо за рассматривание intermediate топиков, таких видео мало. Успехов с каналом!
Спасибо за видос. Понимаю, что возможно упрощение для лучшей доступности материала, но всё же важно подсветить два момента: 1) На стек никто не запрещает положить данные, размер которых заранее неизвестен. Главное, чтобы программа потом смогла подвинуть указатель стека обратно при разрушении объекта. Например gcc может положить на стек массив (именно сами данные) с заранее неизвестным размером. 2) На самом деле есть ещё статическая область данных, и как правило константы располагаются именно в ней, а не на куче (например строковые, как в видео)
1) Только такой элемент данных может быть только один и располагаться в конце стека. Кажется (я пока не изучал это), мало кто до этого использовал такую стратегию (с ваших слов - gcc), но в последних C# что-то такое появилось (могу ошибаться, надо почитать). Если есть инфа, можете поделиться на моем канале где-нибудь в комментах, буду благодарен
@@Uni-Coder да почему один и только в конце? Как устроен стек? Когда кладёшь элемент, записываешь в память данные, и уменьшаешь RSP, указывающий на вершину стека на размер записанных данных. Надо удалить данные со стека - увеличиваешь RSP обратно на тот же размер. Для динамического размера данных надо ещё просто аккуратно записать их размер) Можно самому на ассемблере накидать за 15 минут в качестве развивающего упражнения.
Буду благодарен за ссылки по хранению данных заведомо неизвестного размера в стеке, как и где и зачем это реализовано. Будет интересно почитать. Про статическую область памяти тоже будет интересно почитать. Гуглится sram, но это же не то. Я не спора ради, действительно интересно.
@@vkurilin Это ломает всю компиляцию. Компилятор должен знать смещение каждой переменной от начала стекфрейма, иначе смысла в стеке просто нет, стек перестаёт отличаться от кучи. Можно себе позволить лишь одну переменную на вершине стека с динамической длиной. Немного похоже на переменное число аргументов в C, только здесь вы будете знать хотя бы тип. Вы теоретизируете (что это в принципе возможно) или знаете конкретные примеры?
@@t0digital Покурил документацию. Да, бывает аллокация на стеке. alloca (C), stackalloc(C#). Но ежу понятно, что она ломает компиляцию, т.к. смещение данных от начала стекфрейма становится динамическим.
Спасибо за отличную подачу крайне важной темы. Давно были попытки найти хорошее объяснение работы пайтона с памятью, но только здесь удалось получить наиболее исчерпывающее :)
Очень классный видос, было бы круто, если бы ты сделал такие же видосы про асинхронность и многопоточность: что и когда лучше использовать, какие проблемы они решают, какие у них есть методы и как их лучше использовать и т.д.
Только пример с копией изменяемой структуры не совсем сработает при бОльшей вложенности. Например списки в списках. В копии вложенные структуры будут ссылаться туда же, куда и вложенные в оригинал структуры. В этом случае может помочь функция deepcopy() из пакета copy
так суть именно в обычном копировании, а так можно пройтись рекурсией, чтобы все вложенности скопировать. copy отвечает именно за поверхностую целостность структур, чтобы каждая позиция ссылалась на одну область памяти и выдавать ошибку в случае изменения этой позиции, а какие структуры внутри уже, на это copy чихать. Иными словами, copy не следит за тем, какие структуры внутри основной. Пример с кортежем это подтверждает, область памяти не меняется, вот ему и чихать, какая там структура
Если бы в универе так объяснили материал, то на 2 -ом курсе уже все (или почти все) могли бы стать крутыми программистами. Благодарим за материал. Ждем еще других выпусков.
Я понимаю, что это скорее всего фигура речи, но фактически это неправда. Вот на ютубе лежит весь нужный материал, чтобы стать крутыми программистами. Но что-то не у всех получается, даже у тех кто сильно мотивирован.
Не забываем что преподы работают в лайве, а не записывают видео, где всё можно поправить, никто не задаст никаких вопросов и т.д. А ещё, они не учителя, а именно преподы, понятия разные. Первые - обязаны тебя чему-то научить, а вторые просто преподают материал и в остальном всё зависит от тебя, а не от препода. Так что тут вопрос скорее в самой программе, чем в преподе, хотя я и не отрицаю того, что с хорошим преподом, который хочет научить материал воспринимается чуть легче.
@@dmitriyobidin6049 да нету у меня столько времени чтобы перемалывать все что есть в интернете и на ютубе. как раз подача в таком виде - большая редкость.
@@dmitriyobidin6049 Приветствую! ) 1 - На ютубе редко можно найти материалов которые так понятны и детально разобраны. А если можно найти, то они точно не структурированы и не собраны для конкретной специальностей или направлений как это сделано в универе. Тем более в комментах, я сравнил исключительно подачи и наглядность инфы. 2 - Если даже на ютубе лежит нужный материал (что очень сомневаюсь), то не все кто смотрит ютуб хочет стать программистом. А учащихся в универе, почти все хотят, ибо они как-то готовятся, поступают и вложат свои лучшие годы на учебу. Универ точно имеет свои плюсы в плане развитие чела в приобретение софт скилы, связи и т.д.. 3 - Конечно -же, чтобы становиться "кем-то" , многое завесить от самого человека. Но, для того, чтобы найти достойных материалов, надо оочень стараться и искать зеттабайты инфы из инета.
Впервые наткнулся на канал. Во-первых спасибо за подробности, во-вторых спикер (вероятно автор) молодец в плане хорошо поставленной дикции,, или монтажер молодец, в любом случае приятно слушать инфу без "эээ", "аааа", "ээээммм". Да и инфа полезная. Здорово!
20:43 тут пожалуй новичок может запутаться, первое, что хочется добавить это то что если нужно обезопаситься от изменений объекта в функции методом копирования лучше всего использовать глубокое копирование (from copy import deepcopy), т.к. если у нас список списков при копировании срезом или стандартным методом copy происходит поверхностное копирование ссылок😊 Ещё по поводу аргументов по умолчанию если это сложные объекты лучшей практикой будет указать None, а в самой функции уже присвоить необходимое деыолтное значение. А ну и тут стоит сказать что при передачи в функцию неизменяемых объектов таких накпример как числа связи уже не будет. (При увеличении полученнного числа в функции из вне значение не изменится) Надеюсь хоть кому-то будет полезно) А ещё можно поиграться и посмотреть что при создании нескольких имён на одинаковые неизменчемые объекты (например это особенно интересно со строками) все они будут ссылаться по одному адресу))
Супер, только в примере про getrefcount посчитались не a и b, в них лежит нан так как там был вызов функции. import sys def empty(): pass print(sys.getrefcount(empty)) тоже напечатает 2 :)
да, там надо было не вызывать эту функцию, конечно. import sys def empty(): pass a = empty b = empty c = empty d = empty print(sys.getrefcount(empty)) # 6
Идём в документацию по питону, ищем по слову variable, узнаём, что переменные сущесьвуют. То, что в примере переменная указывает сначала на один объект, потом на другой не делает её не переменной)
Просто в пайтоне нет отличных друг от друга понятий переменная, указатель, ссылка, поэтому всё (очень условно) называется переменной. Но в других многих языках есть и переменные, и указатели, и ссылки, и в этой терминологии именно переменных в пайтоне нет. docs.python.org/3/tutorial/classes.html «Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages.» И там дальше. Это именно то, о чем я говорю. Имена привязываются к объектам, то есть то, что в пайтоне называют переменными по сути это не переменные, это имена, привязанные к объектам.
>> то, что в пайтоне называют переменными по сути это не переменные, это имена, привязанные к объектам. Ну почему же не переменные, вполне себе переменные. Сначала переменная может ссылаться на один объект в памяти, потом на другой. Такие они - переменчивые) Их и в java и в js и C# переменными назывыают. class YavaOrSharp { void m() { var thisIsALocalVariable = new Object(); thisIsALocalVariable = "variated"; } } function js() { var v = new Object(); v = "variated"; }
Все круто, отличная подача для начинающих. Спасибо за проделанную работу) Но есть один момент: Там где идёт работа с функцией empty закралась опечатка/ошибка. В переменные a, b присваивается не объект функции, а непосредственно результат её выполнения. Скобки были лишними.
Давно уже слежу за каналом, но никогда особо не погружался в пайтон, должен признать, что качество обучающих материалов какое-то запредельное (и это бесплатно???), этот канал - недооцененный гем.
Огромное спасибо, очень интересное видео: ты знаешь из этого что-то, но как-то никогда не экспериментировал и смотришь как будто на сакральные знания, воу.
22:40 -- вот как раз пример того, что пространство памяти у функции одно-единственное, сколько бы раз её ни вызывали. И поскольку список в нём не задаётся каждый раз заново, а хранится один и тот же (аж до окончания работы кода в области памяти, объемлющей данную либо пока не удалить принудительно), то эффект логичен и очевиден. "Пространства имён", говорили они, "это круто", говорили они. Так почему бы про них не помнить))
Алексей, спасибо за выпуск! Как всегда все четко и понятно. Единственно пожелание касается вима - мог бы ли ты выводить на экран, что ты вводишь с клавиатуры. Мне как новичку трудновато понять, как все так быстро происходит)
Можно было бы ещё дать комментарий, по поводу того, почему у None и малых значений чисел (0, 1, 2) было так много ссылок: они хранятся в куче в единственном экземпляре для оптимизации. Именно поэтому объект можно сравнивать по адресу с None, а не только через оператор сравнения.
Шикарно! Проясняет многое в языке. Ну и к слову не зря Андрей Столяров настаивает на том что начинать програмировать с Паскаля и освоить работу с указателями в нём. Когда понимаешь что такое указатель и как из них можно собрать хотябы список гораздо проще усвоить вот это поведение пайтона.
Спасибо за видео :) Недавно сам начал изучать Пайтон, делая в процессе игрушку, -- и сегодня долго не мог понять, почему один из алгоритмов не работал, как следует, хотя строки выглядели, как надо. Оказалось, что, когда присваивал одной из "переменных" значение другой, вместо этого происходило что-то иное -- и если значение менялось, то делало это сразу для всех "переменных" :D Когда осознал, что всё, что раньше у себя в коде считал переменными, на самом деле таковыми не являются, а присваивание работает не как присваивание -- испытал лёгкий шок и открыл для себя модуль copy, чтобы копировать значения и больше не бояться. Фух! Благодаря ролику убедился, что всё правильно понял :)
интересное поведение с 6-ю Jack'ами. По сути некорректно ведет себя инициализация значения по умолчанию: интерпретатор зачем-то проверяет существование переменной spisok и не создает ее заново. То есть, правильно так: если не прилетело на вход функции - всегда заново инициировать spisok
В Пайтоне переменные есть , а на уровень ниже , т.е. в интерпретаторе их нет . На уровень ещё ниже переменные снова есть , т.к интерпретатор написан на Си . А на уровень ещё ниже переменных снова нет , там машинный код (регистру процессора без разницы что в него загрузили ) . На следующих уровнях ниже , перечисляю по убыванию : логические вентилях -> транзисторах -> пн-переходах -> атомах -> кварках -----> переменных снова нет
В Питоне есть переменные. Запустите поиск по Python Variables и вы увидите, что все называют это переменными. Они просто неименяемые immutable, меняется не значение переменной, на которую укаызвает имя, а ссылка. То, что техника работы немного другая, это все же перемення. Точно также работают строки в Java или C# и они тоже переменные, потому что изменяется память, на что указывает имя. Все, что вы рассказали - верно, кроме утверждения, что переменных нет.
Кстати, есть один довольно интересный момент связанный с функцией .copy() Она по возможности копирует копирует ссылки, поэтому при работе со списками списков или кортежем списков может вылезти такая проблема, что по меняв элемент в одной последовательности, у вас изменились внутренности и других. Чтобы не попасть в просак лучше в таких случаях использовать .deepcopy(), уж там то гарантированно будут созданы копии и все будет хорошо)
Спасибо за прекрасное объяснение! Но у меня остался один вопрос. Как это в общем это обозвать, что проверяя ссылки на число или None, там было больше ссылок чем в коде(Что бы я мог нагуглить подобные случаи)? Я так понимаю так ссылаются на не изменяемые типы данных, чтобы экономить память.
Я когда начал питон изучать сразу просек это. Переменная это ссылка на адрес в памяти, где значением является типа данных, само имя переменной это ссылка, адрес в памяти хранит значение объекта. Это становится ясно когда изучаешь типы данных что самое начало изучения питона. Мутабельные и немутабельные типы сами кричат об этом, но их мало кто слышит. Как говорится кто слышит, тот будет прогером. Кто нет, просто будет повторять уроки с ютуба и не более
Если falsy значения это ок и их надо грубо привести к пустому листу. Если туда 0 передан по ошибке, он тоже приведется к пустому листу, хотя я бы предпочел, чтобы тут свалилась ошибка, ибо явно что-то пошло не так, если туда ноль попал вместо None или пустого листа
@@t0digital Пардон, я от чего-то решил, что если тип продекларирован, интерпретатор выдаст ошибку, при попытке передать 0 в списочный параметр. На самом деле нет:-(. Молча передает. Удар в спину, не иначе.
Кстати я слышал другое название - идентификатор. Действительно в каком то смысле в py нет переменных. Хотя.... в некоторых языках есть отдельный тип - pointer - и там это наверное все таки переменная - только хранит не значение а ссылку. А в py происходит автоматическое разименование ссылки в значение. Очень хорошее видео,
Да, интересно было бы послушать подробнее про сам интерпретатор, и как на низком уровне он работает. Но довольно непривычно слышать о том, что глобальные переменные (переменные уровня модуля), а точнее их ссылки хранятся в стеке. Обычно я привык с стеку процедурному, потому как в этом есть смысл. Реализация объектной ориетированности Питона несколько непривычна, но знать, с чего начинает свою работу интерпретатор, и чем он ее завершает, было бы полезно. Как реализуются кучи в Питоне, или они пользуют стандартные кучи оси. На низком уровне у нас есть выбор в способе выделения памяти. Там все понятно. Хотелось бы, чтобы кто-то просто и незамысловато приоткрыл этот черный ящик. С удовольствием бы навострил уши вечером за чашечкой крепкого чая с соленой рыбкой.
Для новичков чётко и доходчиво! ) В своё время об значение по умолчанию знатно спотыкался, да. ;-))) Ну и, конечно, по gc и weakrefs тоже полезно будет, ели будет. ;-)
Дорогой мой человек, это прекрасно, что ты разобрался с работой памяти, но от того как ты называешь (представляешь) переменную - в виде коробки или в виде бирки - переменная не перестает быть переменной. Кроме переменных и функций не только в коде, но и в мире ничего нет. Переменные существуют независимо от представлений (сознания) и действий человека... Ну а в остальном было интересно. По крайней мере ты нашел способ привлечь внимание к своему видео.
«Кроме переменных и функций не только в коде, но и в мире ничего нет» А как же сосисочки? Неужели сосисочек не существует? Если серьёзно - переменных не существует, есть только память и данные, которые в ней как-то хранятся:)
22:23 Тут я офигел и выпал в осадок на полчаса. Потом -загуглил- застековерфловил: default arguments are created when the function is loaded (and only once). Значение параметра по умолчанию создаётся единожды. Ну, это неожиданно и не ожидаемо.
В python нет переменных, а есть только объекты, у которых есть адрес в памяти. И вот эти адреса можно назвать каким-то именем, чтобы затем к нужному объекту обратиться.
У вас при подсчете ссылок на empty ошибка. Т.к. вы вызвали empty, для присвоения a и b, то там технически лежат None'ы из-за pass в теле функции. А кол-во ссылок такое из-за объявленной функции и передаче ее, как аргумент, в getrefcount, т.е 2 ссылки. Вы, наверное хотели не вызывать функции, а положить ее в переменные))
На 17:30 ошибка, так как ты вызвал функцию empty, которая вернула None. Нужно было >> a = empty >> b = empty >> sys.getrefcount(empty) 4 Не знаю, стоит ли ещё упомянуть, что в питоне числа от -5 до 256 кешируются (или как правильно?), то есть в памяти только одно по одному числу из этого диапазона: >> a = 256; b = 256 >> a is b True >> a = 257; b = 257 >> a is b False
Пожалуйста можете порекомендовать книги или ресурсы где я могу узнать про python глубже(именно то как работает изнутри)? Просто я искал почему >> a = 256; b = 256 >> a is b True это правильно, вы это узнали с книги или с документации? Заранее спасибо
У вас ошибка на 18:03 import sys def empty(): pass print(sys.getrefcount(empty)) Вот этот код напечатает 2, и этого, в некотором смысле, достаточно. А когда вы делаете a = empty() b = empty() то вы в a и b кладёте ссылки на None, а не на empty. И к той двойке, которую в итоге напечатает код, эти присваивания не имеют никакого отношения.
Интересненько. А вот мне рассказывали, что в Пайтоне все переменные по сути объекты. Теперь я что-то несколько запутался. А ещё интересно как там в куче выделяется место под переменную. Потому как даже тип int в Пайтоне может быть почти бесконечно большим по значению. То, что переммая по сути ссылка на начало понятно. А вот Где конец или как выбирается место под следующую переменную не совсем... Хотя... Хм... Если мы каждый раз храним только конкретное значение, а новое уже по другому адресу, то вроде бы понятно .. но это же какая-то совсем другая концепция использования памяти, которая кажется не совсем оптимальной... Много лишних движений... Хотя.. конечно, это же Пайтон, это не ассемблер, а язык для вышибания из юзеров больше денег на более мощные железки :)
Все значения по сути объекты, а «переменные» это ссылки на адреса ячеек памяти в куче, в которых хранятся эти объекты. Всё это вернёт True: isinstance(1, object) isinstance(False, object) isinstance(None, object) isinstance([], object) isinstance(lambda x: x+1, object)
@@t0digital спасибо. Понятно. Вот такой есть вопрос. Допустим у нас память ПК всего 1Мб и есть переменная а типа int, которая очень большущее число и занимает в памяти 700Кб к примеру. И вот мы пишем а = а + 1. Что будет? Повиснет? Ведь интерпретатор должен выполнить сложение и поместить результат в переменную с тем же именем, но по другому адресу в куче. А места то не хватает, старое то значение всё ещё в памяти.
Помимо физической памяти есть ещё виртуальная, то есть часть диска используется как дополнение оперативки, пусть и с медленной скоростью. Но да, памяти в любом случае может не хватить. Как поведет себя интерпретатор в этом случае - не знаю, не смотрел
Не уверен правильно ли я понял суть ссылок, но я заметил что если в пайтоне написать такой код lst = [1] lst.append(lst) То это приведет к тому, что lst станет как-бы "бесконечно вложенной структурой". Но насколько я понимаю это не так, ведь мы лишь добавляем в lst ссылку на этот же список, а не сам объект lst, потому что иначе такой список lst занимал бы всю память компьютера. И кстати, если немножко поменять код и сделать так lst = [1] lst.append(list(lst)) То в lst действительно добавиться список [1] и получиться [1, [1]]. То есть операция list(lst) создает новый список идентичный lst, но так как это другой список с другим адресом в памяти, никакого списка, содержащего ссылку на самого себя не получается.
В случае с mutable default arg неплохо было бы еще показать, что существует `defaultargs` куда они сохраняются. Для полноты понимания картины так сказать, )
Мой курс «Хардкорная веб-разработка» - course.to.digital
Вжух!
Несмотря на то что я знаю обо всем что говорится в видео, действительно было интересно послушать это в интерпретации Алексея, уверен новичкам зайдет. Однозначно, железобетонный лайк.
Спасибооо!
а я не знал, и было очень интересно
редкий случай когда знал, но сознаваться себе не хотел. Теперь придется с этим жить и об этом невольно думать. И лайк конечно же.
вот зачем нужно учить Си) хотя, я эти нюансы узнал, изучая Pascal, но не суть, полезно учить более низкоуровневые языки
Соглашусь с @binaryman440, хоть и сам владею питоном, но посмотрел почти все видео этого канала.
@t0digital вы тот специалист которого бы хотелось иметь в своей команде. И один и из трех русскоговрящих айти блогеров которых я вообще смотрю.
25 минут видео, чтобы озвучить примерно следующее "В C# существуют две разновидности типов: ссылочные типы и типы значений. В переменных ссылочных типов хранятся ссылки на их данные (объекты), а переменные типа значений содержат свои данные непосредственно. Две переменные ссылочного типа могут ссылаться на один и тот же объект, поэтому операции над одной переменной могут затрагивать объект, на который ссылается другая переменная. При использовании типов значений каждая переменная имеет собственную копию данных, и для операций с одной переменной невозможно повлиять на другую (за исключением inrefслучаев, и out переменных параметров; см. модификатор ref и out). Ну, а в Пайтоне существуют только переменные ссылочного типа, поскольку в Пайтоне всё является объектами".
Спасибо за выпуск. Следующая идея для ролика: Рассказать/показать как работать с утечками в памяти. Думаю, большинству будет полезно как хантиться за memory leaking'ом.
Переменная (программирование) - поименованная, либо адресуемая иным способом область памяти, адрес которой можно использовать для осуществления доступа к данным и изменять значение в ходе выполнения программы.
Если давать такое определение, то объект в куче можно назвать переменной, а в коде мы ссылаемся на эту переменную через ссылки (масло масленное). Ролику конечно лайк в любом случае
Добавлю от себя:
Переменная - именованная область памяти! Указатель это тип переменной, адрес другого места в памяти с данными. Обычно доступен в двух режимах: можно прочесть адрес, а можно значение по этому адресу (обычно в куче). А ссылка это указатель, т.е. переменная типа указатель, которая в обычном режиме получает значение по хранимому адресу, без доступа к указателю, без арифметики указателей, т.е. только один режим доступа, обычно неотличимый от переменной простого типа (целого). Т.е. ссылка это тоже тип переменной. Поэтому "В Python нет переменных, а есть ссылки" это троллинг, свой сленг, может быть допустимый в пределах небольшой песочницы.
@@AlexDanov есть устоявшаяся терминология в языках программирования. Python же не один язык на планете. Вот вы говорите об указателях и ссылках. В питоне же нет явного разделения - вот переменная, вот указатель, вот ссылка. В C++, скажем, есть - и это все 3 разные понятия. Что из этого является «переменной» в Python?
@@kirillgimranov4943 автор не шарит, поясните тупенькому:)
@@t0digital переменная связывает имя со значением, которое можно менять, а не с коробкой! Значением может быть адрес объекта в памяти. Всё как обычно. В конце концов, Python поверх Си работает, из которого берется терминология. Попытка утверждать, что в пайтоне нет переменных это антипаттерн, как кнопки работы с окном слева в MacOS, в противовес кнопкам справа в Windows. Или переставленные кнопки Ok/Cansel. Чтобы "а нефиг!" между платформами прыгать. Аналогично вдруг в Python пропали переменные. Хотелось бы узнать первоисточник этой "мудрости".
@@AlexDanov и всё ж таки вы не ответили на мой вопрос
Открыл для себя хранение данных с абсолютно новой стороны. Раньше вообще не задумывался как и где все это дело хранится. Спасибо!
Отлично!
Алексей, ещё не посмотрел видео, но уже знаю, что будет годнота. Большое спасибо за рассматривание intermediate топиков, таких видео мало. Успехов с каналом!
Так у лутца все написано слово в слово) это база, а не интермидиейт уровень, база которую надо знать как отче наш
Ну как вы это делаете, не туториал а прям полезный подкаст, хочется слушать вас с чайком и печеньками)
А теперь вспоминаем что ссылка - это частный случай переменной)
Хосподя! Спасибо Алексею! Я только изучаю вот это вот все))) Но, в таком доступном формате изложения я еще не встречала! Прям обняла))
Спасибо! Рад, что полезно!
Спасибо за видос. Понимаю, что возможно упрощение для лучшей доступности материала, но всё же важно подсветить два момента:
1) На стек никто не запрещает положить данные, размер которых заранее неизвестен. Главное, чтобы программа потом смогла подвинуть указатель стека обратно при разрушении объекта. Например gcc может положить на стек массив (именно сами данные) с заранее неизвестным размером.
2) На самом деле есть ещё статическая область данных, и как правило константы располагаются именно в ней, а не на куче (например строковые, как в видео)
1) Только такой элемент данных может быть только один и располагаться в конце стека. Кажется (я пока не изучал это), мало кто до этого использовал такую стратегию (с ваших слов - gcc), но в последних C# что-то такое появилось (могу ошибаться, надо почитать). Если есть инфа, можете поделиться на моем канале где-нибудь в комментах, буду благодарен
@@Uni-Coder да почему один и только в конце?
Как устроен стек? Когда кладёшь элемент, записываешь в память данные, и уменьшаешь RSP, указывающий на вершину стека на размер записанных данных.
Надо удалить данные со стека - увеличиваешь RSP обратно на тот же размер. Для динамического размера данных надо ещё просто аккуратно записать их размер)
Можно самому на ассемблере накидать за 15 минут в качестве развивающего упражнения.
Буду благодарен за ссылки по хранению данных заведомо неизвестного размера в стеке, как и где и зачем это реализовано. Будет интересно почитать.
Про статическую область памяти тоже будет интересно почитать. Гуглится sram, но это же не то.
Я не спора ради, действительно интересно.
@@vkurilin Это ломает всю компиляцию. Компилятор должен знать смещение каждой переменной от начала стекфрейма, иначе смысла в стеке просто нет, стек перестаёт отличаться от кучи. Можно себе позволить лишь одну переменную на вершине стека с динамической длиной. Немного похоже на переменное число аргументов в C, только здесь вы будете знать хотя бы тип.
Вы теоретизируете (что это в принципе возможно) или знаете конкретные примеры?
@@t0digital Покурил документацию. Да, бывает аллокация на стеке. alloca (C), stackalloc(C#). Но ежу понятно, что она ломает компиляцию, т.к. смещение данных от начала стекфрейма становится динамическим.
Алексей, спасибо за выпуск!
Рассмотрите, пожалуйста, тему "Утечки памяти в Python", мало кто задумывается об этом, в нашем любимом языке (
Спасибо за отличную подачу крайне важной темы. Давно были попытки найти хорошее объяснение работы пайтона с памятью, но только здесь удалось получить наиболее исчерпывающее :)
Спасибо!
Очень классный видос, было бы круто, если бы ты сделал такие же видосы про асинхронность и многопоточность: что и когда лучше использовать, какие проблемы они решают, какие у них есть методы и как их лучше использовать и т.д.
Только пример с копией изменяемой структуры не совсем сработает при бОльшей вложенности. Например списки в списках. В копии вложенные структуры будут ссылаться туда же, куда и вложенные в оригинал структуры. В этом случае может помочь функция deepcopy() из пакета copy
так суть именно в обычном копировании, а так можно пройтись рекурсией, чтобы все вложенности скопировать. copy отвечает именно за поверхностую целостность структур, чтобы каждая позиция ссылалась на одну область памяти и выдавать ошибку в случае изменения этой позиции, а какие структуры внутри уже, на это copy чихать. Иными словами, copy не следит за тем, какие структуры внутри основной.
Пример с кортежем это подтверждает, область памяти не меняется, вот ему и чихать, какая там структура
@@БорисОстроумов-т7к если бы ваш ответ было возможно прочитать - было бы намного лучше)
Если бы в универе так объяснили материал, то на 2 -ом курсе уже все (или почти все) могли бы стать крутыми программистами. Благодарим за материал. Ждем еще других выпусков.
Я понимаю, что это скорее всего фигура речи, но фактически это неправда. Вот на ютубе лежит весь нужный материал, чтобы стать крутыми программистами. Но что-то не у всех получается, даже у тех кто сильно мотивирован.
Не забываем что преподы работают в лайве, а не записывают видео, где всё можно поправить, никто не задаст никаких вопросов и т.д.
А ещё, они не учителя, а именно преподы, понятия разные. Первые - обязаны тебя чему-то научить, а вторые просто преподают материал и в остальном всё зависит от тебя, а не от препода. Так что тут вопрос скорее в самой программе, чем в преподе, хотя я и не отрицаю того, что с хорошим преподом, который хочет научить материал воспринимается чуть легче.
@@dmitriyobidin6049 да нету у меня столько времени чтобы перемалывать все что есть в интернете и на ютубе. как раз подача в таком виде - большая редкость.
@@Gabriel-hg7fl Я имел в виду именно подход и метод подачи материалов по наглядности и доступности.
@@dmitriyobidin6049 Приветствую! )
1 - На ютубе редко можно найти материалов которые так понятны и детально разобраны. А если можно найти, то они точно не структурированы и не собраны для конкретной специальностей или направлений как это сделано в универе. Тем более в комментах, я сравнил исключительно подачи и наглядность инфы.
2 - Если даже на ютубе лежит нужный материал (что очень сомневаюсь), то не все кто смотрит ютуб хочет стать программистом. А учащихся в универе, почти все хотят, ибо они как-то готовятся, поступают и вложат свои лучшие годы на учебу. Универ точно имеет свои плюсы в плане развитие чела в приобретение софт скилы, связи и т.д..
3 - Конечно -же, чтобы становиться "кем-то" , многое завесить от самого человека. Но, для того, чтобы найти достойных материалов, надо оочень стараться и искать зеттабайты инфы из инета.
Впервые наткнулся на канал. Во-первых спасибо за подробности, во-вторых спикер (вероятно автор) молодец в плане хорошо поставленной дикции,, или монтажер молодец, в любом случае приятно слушать инфу без "эээ", "аааа", "ээээммм". Да и инфа полезная. Здорово!
20:43 тут пожалуй новичок может запутаться, первое, что хочется добавить это то что если нужно обезопаситься от изменений объекта в функции методом копирования лучше всего использовать глубокое копирование (from copy import deepcopy), т.к. если у нас список списков при копировании срезом или стандартным методом copy происходит поверхностное копирование ссылок😊
Ещё по поводу аргументов по умолчанию если это сложные объекты лучшей практикой будет указать None, а в самой функции уже присвоить необходимое деыолтное значение.
А ну и тут стоит сказать что при передачи в функцию неизменяемых объектов таких накпример как числа связи уже не будет. (При увеличении полученнного числа в функции из вне значение не изменится)
Надеюсь хоть кому-то будет полезно)
А ещё можно поиграться и посмотреть что при создании нескольких имён на одинаковые неизменчемые объекты (например это особенно интересно со строками) все они будут ссылаться по одному адресу))
Побольше такого контента пожалуйста!
Буду делать, спасибооо!
Супер, только в примере про getrefcount посчитались не a и b, в них лежит нан так как там был вызов функции.
import sys
def empty(): pass
print(sys.getrefcount(empty))
тоже напечатает 2 :)
да, там надо было не вызывать эту функцию, конечно.
import sys
def empty(): pass
a = empty
b = empty
c = empty
d = empty
print(sys.getrefcount(empty)) # 6
Спасибо, интересно. Обычно я смотрю видео на английском, они как правило полнее и лучше структурированы, ваши видео как раз хорошее исключение.
Спасибооо!
Идём в документацию по питону, ищем по слову variable, узнаём, что переменные сущесьвуют. То, что в примере переменная указывает сначала на один объект, потом на другой не делает её не переменной)
Но суть понятна, в питоне все переменные ссылочные (это я из видео подчеркнул, если это не так, не обижайтесь, я не проверял).
в пайтоне "всё есть объект" в том числе и объекты выполняющие функции переменной. отсюда и заголовок. вы немножечко не смогли в иронию.
Почитайте всё же документацию.
Просто в пайтоне нет отличных друг от друга понятий переменная, указатель, ссылка, поэтому всё (очень условно) называется переменной. Но в других многих языках есть и переменные, и указатели, и ссылки, и в этой терминологии именно переменных в пайтоне нет.
docs.python.org/3/tutorial/classes.html
«Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages.»
И там дальше. Это именно то, о чем я говорю. Имена привязываются к объектам, то есть то, что в пайтоне называют переменными по сути это не переменные, это имена, привязанные к объектам.
>> то, что в пайтоне называют переменными по сути это не переменные, это имена, привязанные к объектам.
Ну почему же не переменные, вполне себе переменные. Сначала переменная может ссылаться на один объект в памяти, потом на другой. Такие они - переменчивые) Их и в java и в js и C# переменными назывыают.
class YavaOrSharp {
void m() {
var thisIsALocalVariable = new Object();
thisIsALocalVariable = "variated";
}
}
function js() {
var v = new Object();
v = "variated";
}
Очень годное видео! Все эти "подкапотные штуки" - очень интересная тема и её очень мало в русскоязычном сегменте youtube или блогосфере. Спасибо!
Все круто, отличная подача для начинающих. Спасибо за проделанную работу)
Но есть один момент:
Там где идёт работа с функцией empty закралась опечатка/ошибка. В переменные a, b присваивается не объект функции, а непосредственно результат её выполнения. Скобки были лишними.
Давно уже слежу за каналом, но никогда особо не погружался в пайтон, должен признать, что качество обучающих материалов какое-то запредельное (и это бесплатно???), этот канал - недооцененный гем.
Спасибооо!
Круто, очень интересно!
Огромнейшая благодарность!
Большое спасибо! Высший пилотаж рассказчика)
Спасибооо!
скажу кратко: просто и доступно!
Спасибо! Гениальное видео! Пожалуйста, сделай видео про unix утилиты sed и awk
В начале ролика я думал , что наконец появился человек который не использует картонных коробок в программировании. Как я жестоко ошибался.
Держитесь, крепитесь, сил вам!
Огромное спасибо, очень интересное видео: ты знаешь из этого что-то, но как-то никогда не экспериментировал и смотришь как будто на сакральные знания, воу.
7:34 Он все таки проговорился: вот, напимер, создаем переменную first_name... D)
Насчет последнего (20:41) всегда принимал за истину, т.к. это описано в PEP, а теперь предельно ясен данный момент. Алексей, спасибо
22:40 -- вот как раз пример того, что пространство памяти у функции одно-единственное, сколько бы раз её ни вызывали. И поскольку список в нём не задаётся каждый раз заново, а хранится один и тот же (аж до окончания работы кода в области памяти, объемлющей данную либо пока не удалить принудительно), то эффект логичен и очевиден.
"Пространства имён", говорили они, "это круто", говорили они. Так почему бы про них не помнить))
Алексей, спасибо за выпуск! Как всегда все четко и понятно. Единственно пожелание касается вима - мог бы ли ты выводить на экран, что ты вводишь с клавиатуры. Мне как новичку трудновато понять, как все так быстро происходит)
это не будет отвлекать:)?
@@t0digital не знаю) Погуглил и нашел как я это себе представлял - ua-cam.com/video/bSMZgXzC9AA/v-deo.html
Дуже цікаве та корисне відео, дякую)
Качественно записано/сделано, хорошо поставленная речь - приятно слушать. Надеюсь и дальше продолжите рассматривать углублённые темы, очень интересно
Спасибоо🙏
Алексей, ты что-то вес набрал. Держи себя в форме, не расплывайся )) За ролики спасибо ))
Спасибо в любом случае за старания) но хотелось бы более глубоких и неочевидных вещей.
Это видео возникло как ответ на один вопрос на курсе. Судя по комментам не для всех тут материал очевиден:)
Если кому-то начать объяснять почему в пайтон нет переменных, то сразу откроют форточку от духоты))))
За видос спасибо!
Ну да)))
Большое спасибо за интересную подачу, важного новичкам материала
Спасибо!
Можно было бы ещё дать комментарий, по поводу того, почему у None и малых значений чисел (0, 1, 2) было так много ссылок: они хранятся в куче в единственном экземпляре для оптимизации. Именно поэтому объект можно сравнивать по адресу с None, а не только через оператор сравнения.
Хороший видос. Спасибо.
Шикарно! Проясняет многое в языке.
Ну и к слову не зря Андрей Столяров настаивает на том что начинать програмировать с Паскаля и освоить работу с указателями в нём. Когда понимаешь что такое указатель и как из них можно собрать хотябы список гораздо проще усвоить вот это поведение пайтона.
Алексей, очень круто!
Если можно, то больше таких видео!
Круто!))
Я теперь в теме, меня теперь не обмануть !)
Спасибо за видео :)
Недавно сам начал изучать Пайтон, делая в процессе игрушку, -- и сегодня долго не мог понять, почему один из алгоритмов не работал, как следует, хотя строки выглядели, как надо. Оказалось, что, когда присваивал одной из "переменных" значение другой, вместо этого происходило что-то иное -- и если значение менялось, то делало это сразу для всех "переменных" :D Когда осознал, что всё, что раньше у себя в коде считал переменными, на самом деле таковыми не являются, а присваивание работает не как присваивание -- испытал лёгкий шок и открыл для себя модуль copy, чтобы копировать значения и больше не бояться.
Фух! Благодаря ролику убедился, что всё правильно понял :)
интересное поведение с 6-ю Jack'ами. По сути некорректно ведет себя инициализация значения по умолчанию: интерпретатор зачем-то проверяет существование переменной spisok и не создает ее заново. То есть, правильно так: если не прилетело на вход функции - всегда заново инициировать spisok
Очень круто!
Шедевр
Интересно. Спасибо.
- В Пайтон нет переменных: сишники вышли из чата
- Я не поехал кукухой: джаваскриптизеры вышли из чата
Классное видео! Спасибо! А можно такое же про asyncio, конкаренси и мультисрединг подходы в питоне.
Алексей, спасибо за видос
Спасибооо!
Спасибо! Очень познавательно.
В Пайтоне переменные есть , а на уровень ниже , т.е. в интерпретаторе их нет . На уровень ещё ниже переменные снова есть , т.к интерпретатор написан на Си . А на уровень ещё ниже переменных снова нет , там машинный код (регистру процессора без разницы что в него загрузили ) . На следующих уровнях ниже , перечисляю по убыванию : логические вентилях -> транзисторах -> пн-переходах -> атомах -> кварках -----> переменных снова нет
Спасибо за видео.
В Питоне есть переменные. Запустите поиск по Python Variables и вы увидите, что все называют это переменными. Они просто неименяемые immutable, меняется не значение переменной, на которую укаызвает имя, а ссылка. То, что техника работы немного другая, это все же перемення. Точно также работают строки в Java или C# и они тоже переменные, потому что изменяется память, на что указывает имя.
Все, что вы рассказали - верно, кроме утверждения, что переменных нет.
Спасибо большое, очень помогло ваше видео
Интересно, спасибо )
Кстати, есть один довольно интересный момент связанный с функцией .copy()
Она по возможности копирует копирует ссылки, поэтому при работе со списками списков или кортежем списков может вылезти такая проблема, что по меняв элемент в одной последовательности, у вас изменились внутренности и других.
Чтобы не попасть в просак лучше в таких случаях использовать .deepcopy(), уж там то гарантированно будут созданы копии и все будет хорошо)
да, для вложенных структур есть deepcopy
Спасибо за прекрасное объяснение! Но у меня остался один вопрос. Как это в общем это обозвать, что проверяя ссылки на число или None, там было больше ссылок чем в коде(Что бы я мог нагуглить подобные случаи)? Я так понимаю так ссылаются на не изменяемые типы данных, чтобы экономить память.
Я когда начал питон изучать сразу просек это. Переменная это ссылка на адрес в памяти, где значением является типа данных, само имя переменной это ссылка, адрес в памяти хранит значение объекта. Это становится ясно когда изучаешь типы данных что самое начало изучения питона. Мутабельные и немутабельные типы сами кричат об этом, но их мало кто слышит. Как говорится кто слышит, тот будет прогером. Кто нет, просто будет повторять уроки с ютуба и не более
Очень годное объяснение, большое спасибо! Хотелось бы видосики в таком же стиле по алгоритмам и по static и class methods.
Доходчиво
По поводу инициализации мутабельных параметров в теле функции(24:12). Можно, например, сделать так: "names = names or []"
Если falsy значения это ок и их надо грубо привести к пустому листу. Если туда 0 передан по ошибке, он тоже приведется к пустому листу, хотя я бы предпочел, чтобы тут свалилась ошибка, ибо явно что-то пошло не так, если туда ноль попал вместо None или пустого листа
@@t0digital Пардон, я от чего-то решил, что если тип продекларирован, интерпретатор выдаст ошибку, при попытке передать 0 в списочный параметр. На самом деле нет:-(. Молча передает. Удар в спину, не иначе.
18:00 - косяк. Функция empty вызывается, на неё не берётся ссылка. Если написать a = empty, b = empty, то getrefcount(empty) вернёт 4
Спасибо, подробно, интересно и полезно.
Спасибо очень доступно объяснили
Не ну всё, теперь переписываем все учебники по питону, где "ссылки" называются "переменные"
Теперь да!
Алексей, большое спасибо вам за ваши видео!
Если не сложно, то назовите ваши топ-3 (а может и топ-5) тем в vim, просто интересно)
Они у меня плавающие - когда надоедает, ставлю новую:) Сейчас gruvbox стоит, гитхаб morhetz/gruvbox
Catppuccin, моднее просто нет
@@t0digital спасибо)
Последний пример слегка удивил. Не знал, что функция может так работать. Спасибо.
Кстати я слышал другое название - идентификатор. Действительно в каком то смысле в py нет переменных. Хотя.... в некоторых языках есть отдельный тип - pointer - и там это наверное все таки переменная - только хранит не значение а ссылку. А в py происходит автоматическое разименование ссылки в значение. Очень хорошее видео,
Объяснил супер, но раз такая пляска, то надо было ещё рассказать про циклические ссылки и Generation Garbage Collector
показалось это не очень интересным:)
@@t0digital к сожалению, на собеседованиях процентов 95 кандидатов вообще о нем не слышали((
@@vyacheslavrineisky1890 я никогда такого на собеседах не спрашивал. Вы спрашиваете, считаете важным?
@@t0digital на middle, если человек в остальном был хорош, на senior почти всегда
Начало объясняет азы плюсов)), стек , куча
Да, интересно было бы послушать подробнее про сам интерпретатор, и как на низком уровне он работает. Но довольно непривычно слышать о том, что глобальные переменные (переменные уровня модуля), а точнее их ссылки хранятся в стеке. Обычно я привык с стеку процедурному, потому как в этом есть смысл. Реализация объектной ориетированности Питона несколько непривычна, но знать, с чего начинает свою работу интерпретатор, и чем он ее завершает, было бы полезно. Как реализуются кучи в Питоне, или они пользуют стандартные кучи оси. На низком уровне у нас есть выбор в способе выделения памяти. Там все понятно. Хотелось бы, чтобы кто-то просто и незамысловато приоткрыл этот черный ящик. С удовольствием бы навострил уши вечером за чашечкой крепкого чая с соленой рыбкой.
Хоба! Вот это подгон, спасибо! И я снова котан
Знал об этом, но материал подан качественно, начинающим обязательно к просмотру)
Лайк просто с разбегу!))
18:04 a и b все-таки ссылаются на None, а на объект функции empty ссылается только переменная empty
Не надо было вызывать функцию, да.
import sys
def empty(): pass
a = empty
b = empty
c = empty
d = empty
print(sys.getrefcount(empty)) # 6
@@t0digital добавьте в описание ролика, замордуют)
Просто капитальный красавчик
Смотрю тебя с самого основания канала. Последнее время наблюдаю у тебя очки и сам замечаю что зрение уже не то, что в школе. Эх, стареем...
Для новичков чётко и доходчиво! ) В своё время об значение по умолчанию знатно спотыкался, да. ;-))) Ну и, конечно, по gc и weakrefs тоже полезно будет, ели будет. ;-)
Дорогой мой человек, это прекрасно, что ты разобрался с работой памяти, но от того как ты называешь (представляешь) переменную - в виде коробки или в виде бирки - переменная не перестает быть переменной. Кроме переменных и функций не только в коде, но и в мире ничего нет. Переменные существуют независимо от представлений (сознания) и действий человека... Ну а в остальном было интересно. По крайней мере ты нашел способ привлечь внимание к своему видео.
«Кроме переменных и функций не только в коде, но и в мире ничего нет»
А как же сосисочки? Неужели сосисочек не существует?
Если серьёзно - переменных не существует, есть только память и данные, которые в ней как-то хранятся:)
на 13:00 должна была сработать кешировання память в пайтоне, тоесть сравнивание с оператором "is" тоже должен был вернуть True
А разве mutable типы кешируются?
@@t0digital точно, со строкой было бы True
@@Bandera_tut короткие строки да. Длинные уже нет
Узнал новое, спасибо
Спасибо) Посмотрел как "Спокойной ночи, малыши" - и полезно, и как-то прям успокаивает) /*наверно, просто устал*/
Просмотрел видео до конца после просмотра лекций Хирьянова, он как раз объяснял материал основываясь на коробках, куда добавлял значения :)
22:23 Тут я офигел и выпал в осадок на полчаса. Потом -загуглил- застековерфловил: default arguments are created when the function is loaded (and only once). Значение параметра по умолчанию создаётся единожды.
Ну, это неожиданно и не ожидаемо.
Так и есть
@@t0digital Интересная ситуация, я бы сам до неё не допёр. Сошлюсь на это видео на своём канале.
это очень глубокий подводный камень, напороться на него будет дорогого стоить в плане отладки
@@grieverrr Сам удивляюсь, что до сих пор не напоролся.
@@t0digital Выпустил у себя видео, на тебя сослался. Примерно 22:30
В python нет переменных, а есть только объекты, у которых есть адрес в памяти. И вот эти адреса можно назвать каким-то именем, чтобы затем к нужному объекту обратиться.
У вас при подсчете ссылок на empty ошибка. Т.к. вы вызвали empty, для присвоения a и b, то там технически лежат None'ы из-за pass в теле функции. А кол-во ссылок такое из-за объявленной функции и передаче ее, как аргумент, в getrefcount, т.е 2 ссылки. Вы, наверное хотели не вызывать функции, а положить ее в переменные))
На 17:30 ошибка, так как ты вызвал функцию empty, которая вернула None. Нужно было
>> a = empty
>> b = empty
>> sys.getrefcount(empty)
4
Не знаю, стоит ли ещё упомянуть, что в питоне числа от -5 до 256 кешируются (или как правильно?), то есть в памяти только одно по одному числу из этого диапазона:
>> a = 256; b = 256
>> a is b
True
>> a = 257; b = 257
>> a is b
False
Пожалуйста можете порекомендовать книги или ресурсы где я могу узнать про python глубже(именно то как работает изнутри)?
Просто я искал почему
>> a = 256; b = 256
>> a is b
True
это правильно, вы это узнали с книги или с документации?
Заранее спасибо
Благодарю
У вас ошибка на 18:03
import sys
def empty():
pass
print(sys.getrefcount(empty))
Вот этот код напечатает 2, и этого, в некотором смысле, достаточно.
А когда вы делаете
a = empty()
b = empty()
то вы в a и b кладёте ссылки на None, а не на empty. И к той двойке, которую в итоге напечатает код, эти присваивания не имеют никакого отношения.
Интересненько. А вот мне рассказывали, что в Пайтоне все переменные по сути объекты. Теперь я что-то несколько запутался. А ещё интересно как там в куче выделяется место под переменную. Потому как даже тип int в Пайтоне может быть почти бесконечно большим по значению. То, что переммая по сути ссылка на начало понятно. А вот Где конец или как выбирается место под следующую переменную не совсем... Хотя... Хм... Если мы каждый раз храним только конкретное значение, а новое уже по другому адресу, то вроде бы понятно .. но это же какая-то совсем другая концепция использования памяти, которая кажется не совсем оптимальной... Много лишних движений... Хотя.. конечно, это же Пайтон, это не ассемблер, а язык для вышибания из юзеров больше денег на более мощные железки :)
Все значения по сути объекты, а «переменные» это ссылки на адреса ячеек памяти в куче, в которых хранятся эти объекты.
Всё это вернёт True:
isinstance(1, object)
isinstance(False, object)
isinstance(None, object)
isinstance([], object)
isinstance(lambda x: x+1, object)
@@t0digital спасибо. Понятно. Вот такой есть вопрос.
Допустим у нас память ПК всего 1Мб и есть переменная а типа int, которая очень большущее число и занимает в памяти 700Кб к примеру. И вот мы пишем а = а + 1.
Что будет? Повиснет?
Ведь интерпретатор должен выполнить сложение и поместить результат в переменную с тем же именем, но по другому адресу в куче. А места то не хватает, старое то значение всё ещё в памяти.
Помимо физической памяти есть ещё виртуальная, то есть часть диска используется как дополнение оперативки, пусть и с медленной скоростью. Но да, памяти в любом случае может не хватить. Как поведет себя интерпретатор в этом случае - не знаю, не смотрел
Не уверен правильно ли я понял суть ссылок, но я заметил что если в пайтоне написать такой код
lst = [1]
lst.append(lst)
То это приведет к тому, что lst станет как-бы "бесконечно вложенной структурой". Но насколько я понимаю это не так, ведь мы лишь добавляем в lst ссылку на этот же список, а не сам объект lst, потому что иначе такой список lst занимал бы всю память компьютера.
И кстати, если немножко поменять код и сделать так
lst = [1]
lst.append(list(lst))
То в lst действительно добавиться список [1] и получиться [1, [1]]. То есть операция list(lst) создает новый список идентичный lst, но так как это другой список с другим адресом в памяти, никакого списка, содержащего ссылку на самого себя не получается.
Премного благодарен за контент!
Уважаемые слушатели, самое пристальное внимание акцентируйте на 09:05-09:40🤝
В случае с mutable default arg неплохо было бы еще показать, что существует `defaultargs` куда они сохраняются. Для полноты понимания картины так сказать, )
Что за defaultargs?