У Вас отличный контент, Сергей. Давно присматривался к каналу, но я относительно недавно в питоне и раньше материал казался сложноватым. Но наконец дорос и смотрю теперь с удовольствием! Спасибо огромное!
Спасибо вам большое Сергей!Уже скоро кончится курс по ООП, потом буду смотреть ваш курс по Django!Вы единственный человек который рассказывает подробно про все темы!
Урок #32 = Пройден Этот урок меня настолько запутал, что пришлось обращаться к chatGPT, который тоже сначала не мог объяснить, ибо использовал примеры с sql, и т д, но я его попросил объяснить чтобы и дерево поняло, и в итоге, я все понял 🤣🤣 Менеджер with оказался очень даже полезным, и интересным :)
все понятно кроме self.__v[:] = self.__temp вроде более логичной выглядит запись self.__v = self.__temp но тогда self.__v приобретает ссылку на другой объект (изменяется id), а v1 продолжает ссылаться на изначальный список со старым id после присвоения self.__v[:] = self.__temp self.__v стал ссылаться на другой список, при том у него остался изначальный id за ним поменяется и v1 Получается, в результате self.__v[:] = self.__temp старый список затирается и там где он хранился в памяти возникает новый список? не понимаю логику. можно где то подробнее это разузнать?
Это равносильно, что менять какой-либо элемент в списке, например: my_list[1,2,3,] -> my_list[0] = 12. Такая же логика и там, мы берем срез от начал и до конца, тем самым изменяем значения всего списка на значения из другого. Надеюсь понятно объяснил )
нет, v1 и _v ссылаются на один и тот же объект, который не затирается, а просто изменяется, потому что список это изменяемый тип данных, со строкой либо кортежем такой бы трюк не прокатил, потому что там бы в любом случае создавался новый объект, на который бы ссылался только _v
Думаю стоило упомянуть хотя-бы разок, что используя конструкцию среза вы получаете поверхностную копию списка, для полного копирования (например когда у вас список объектов) можно использовать deepcopy из библиотеки copy.
Уже вроде и с ООП разобрался, декораторы, генераторы, на джанго и DRF написал несколько приложений, но вот менеджер контекста все равно вызывает у меня трудности. 😅
Два дня не мог понять, почему при изменении "self.__v" меняется сам "v1", ведь нигде нет кода типа: "v1 = self.__v[:]". В итоге до меня дошло, что "v1", "v", "self.__v" это все ссылки на один и тот же список, у них у всех один и тот же id, и меняя один мы меняем все остальные.
Переменная экземпляра класса DefendVector self.__v ссылается на тот же объект что и глобальная переменная v1(т.е. на лист [1, 2, 3]). И для того, чтобы не менять ссылки(т.е. переменные) автор меняет значения списка(в данном случае наш объект). Если две переменные ссылаются на один и тот же объект, это значит, что они зависят друг от друга, измени в одной переменной значение списка, оно также поменяется и в другой переменной, которая ссылается на тот же самый объект. Если бы автор записал так self.__v = self.__temp, это значило бы, что переменная __v ссылается уже абсолютно на другой объект, в данном случае это введет к тому, что переменная v1, осталась бы без изменений, так как __v это уже независимый объект, и v1 никаким образом не подтянет тех изменений, которые произошли в переменной __v.
В ООП существуют различные исключения, которые генерируются командой raise. Когда оно появлявляется, то программа должна либо обработать его, либо оно будет подниматься до точки старта программы. Если и там не обработается, то программа завершит свою работу.
подскажи пожалуйста не могу врубиться) то что мы делаем в def __enter__ когда копируем список через self.__temp = self.__v[:] понятно. а то что мы делаем в def __exit__ когда обратно копируем уже измененный список self.__v[:] = self.__temp в self.__v. что тут делает [:] непонятно(
@@artbog спасиб, я гуглил) но врубился только после твоей подсказки) если синтаксис b = a[:] то мы копируем все значения из одного списка и в другой (создается новые объект). Но если мы делаем так a[:] = b, том мы возвращаем срезом ту часть списка которую хотим заменить, новым списком, заменяем ее значениями на значения списка "b", а остальные оставляем, при этом ссылка на объект "a" остается неизменной.
@@genghiskhan8835 я понимаю так: если мы делаем a = b, то в переменную a копируем ссылку на объект из переменной b. Но если мы делаем a[:] = b то переменная a смотрит на тот же объект что и раньше (на видео это список [1, 2, 3]) и меняются сами значения в этом списке, сама ссылка на объект остается неизменной. это нам как раз и нужно по задаче, чтобы в случае успешного изменения нужный нам объект менялся, в случае неуспешного оставался неизменным. Короче разница что если сделать a = b, то в примере на видео мы в конце будем вызывать print(v1) и объект на который ссылает переменная v1 никогда не будет меняться, хоть успешно все прошло хоть нет.
в UI библиотеке Gradio очень непонятное использование менеджера контекста import gradio as gr with gr.Blocks() as demo: gr.Markdown("...") with gr.Tab("Flip Text"): gr.Markdown("...") demo.launch() Не понятно как это работает)
Вопрос на 7й минуте - когда мы создаём enter метод, присходит переприсваивание, и таким образом копируем объект, копирование поверхностное или глубокое?.. вообще в питоне при вот таком переприсваивании какое копирование происходит?..
предыдущий материал курса ООП зашел на ура. но в этой теме возникла какая-то каша. 1) на 2.50 Вы пишете заголовок слайда "Менеджер контекста (with)" и вначале говорите "ключевое слово with, то есть это и есть менеджер контекста". на том же слайде на 2.50 написано, что менеджер контекста идет после ключевого слова with. так что из этого все же менеджер контекста? 2) еще больше путаницы внес первый тест после видео. один из вариантов ответа "менеджер контекста образует свою локальную область видимости (подобно функциям, тело которых находится внутри локальной области видимости)". в видео же вы создаете менеджер контекста - класс DefenderVector, далее пользуетесь экземпляром этого класса как менеджером контекста. т.е. у менеджера контекста есть своя локальная область видимости, в которой при инициализации формируется переменная self.__v. тогда почему указанный вариант ответа в тесте неправильный? исходя из того, что этот вариант ответа не верный, стоит полагать все же что менеджер контекста это with? однако для примера создания менеджера контекста вы прописываете то, что идет ПОСЛЕ with. 3) допустим, менеджер контекста - это объект после with. тогда если мы пишем with open('file') as file менеджером контекста будет open()? но ведь это же стандартная функция питона, а не менеджер контекста. Уважаемый Сергей, очень ценю Ваш труд, понимаю что материала много и грамотно его структурировать - не простая задача. в этот раз получилось как-то запутанно
Я, конечно, не могу говорить с точной уверенностью, но как я понимаю и знаю, контекстный менеджер это то, что идет после with, ибо контекстный менеджер это класс, который содержит два магических метода __enter__ и __exit__ , а ключевое слово with существует, для того чтобы в правильном порядке вызывать данные магические методы. И как вы заметили, функция open() является по факту классом, который как раз таки и имеет эти два метода
Подскажите пожалуйста, почему в методе exit обязательно надо использовать срез: self.__v[:] = self. __temp Если срез не использовать, то список v1 не меняется
Этот код меняет только содержимое объекта, в обратном случае self.__v = self. __temp переменной self.__v присваивается новый объект, который был создан в __temp. Оригинальный список v1 больше не изменяется, так как self.__v теперь указывает на другой объект, ссылки на v1 за пределами контекстного менеджера останутся прежними, и их содержимое не изменится.
Сергей, спасибо большое за видео! Я не особо понял момент на 7:35 с 11 строкой, почему там [:] у srlf.__v? Я не особо понимаю как это работает в данном случае, прошу объяснить этот момент)
@@dkuz Внутри этой штуки: with DefenerVector(v1) as dv: мы должны работать с копией списка, т.к. если что то пойдет не так, иметь возможность его восстановить
Спасибо! Получается, что open это все таки не функция, а целый класс, где реализованы методы enter, exit, call? Т.е. мы можем в свой любой класс добавить функциональность менеджера контекста?
Нет, open это функция, которая возращает менеджер контекста. Вы можете сами сдеать подобную функцию: class MyContext: def __init__(self, v): self.__v = v def __enter__(self): self.__tmp = self.__v[:] return self.__tmp
def __exit__(self, *exc): self.__v[:] = self.__tmp return False def give_context(v): return MyContext(v) a = [1, 2, 3] b = [2, 2] # b = [2, 2, 2] with give_context(a) as v: for i in range(len(v)): v[i] += b[i] print(a)
Спасибо за урок! Хочу задать вопрос, как вы выделяя несколько строк помещаете их все в комментарии (# перед всеми) или ставите перед всеми отступ (tab)? Просто когда я так делаю в pycharm, строки попросту заменяются. Это настраивается как - то? Заранее спасибо.
Я правильно понимаю, что именно слово with определяет порядок вызова и делает сам вызов методов __enter__, __exit__ ? потому как код dv = DefendVector(v1)... не работает, хотя методы в классе переопределены
Для чего нужен менеджер контекста и где его применять?.. для безопасности кода и применять везде где только можно. Имхо. Потому как класс который создаёт объект и должен его уничтожать… особенно если вы работаете с ресурсами. Инициализация как захват ресурса
8:50 - я и мой курсач по проге
"Здесь конечно ошибка должна быть, но другая"
Мужрые слова)😅
Официально заявляю. Более полезных уроков по питону, я не видел. Двужище, ты лучший.
У Вас отличный контент, Сергей. Давно присматривался к каналу, но я относительно недавно в питоне и раньше материал казался сложноватым. Но наконец дорос и смотрю теперь с удовольствием! Спасибо огромное!
Спасибо вам большое Сергей!Уже скоро кончится курс по ООП, потом буду смотреть ваш курс по Django!Вы единственный человек который рассказывает подробно про все темы!
Большое спасибо за замечательный урок и за этот курс!!!
Спасибо за реально крутое объяснение менеджера контекста.
Спасибо. Очень круто!
Отличный пример избыточности, заложенной в ООП.
Спасибо за уроки!
Великолепный урок! Спасибо за то, что Вы делаете)
Классное объяснение!
Урок #32 = Пройден
Этот урок меня настолько запутал, что пришлось обращаться к chatGPT, который тоже сначала не мог объяснить, ибо использовал примеры с sql, и т д, но я его попросил объяснить чтобы и дерево поняло, и в итоге, я все понял 🤣🤣
Менеджер with оказался очень даже полезным, и интересным :)
Хорошие уроки. Нам ещё везёт что нет задании. ☺️☺️☺️
все понятно кроме
self.__v[:] = self.__temp
вроде более логичной выглядит запись
self.__v = self.__temp
но тогда self.__v приобретает ссылку на другой объект (изменяется id), а v1 продолжает ссылаться на изначальный список со старым id
после присвоения self.__v[:] = self.__temp
self.__v стал ссылаться на другой список, при том у него остался изначальный id
за ним поменяется и v1
Получается, в результате self.__v[:] = self.__temp
старый список затирается и там где он хранился в памяти возникает новый список?
не понимаю логику. можно где то подробнее это разузнать?
Если ты разобрался, объясни пожалуйста
Это равносильно, что менять какой-либо элемент в списке, например: my_list[1,2,3,] -> my_list[0] = 12. Такая же логика и там, мы берем срез от начал и до конца, тем самым изменяем значения всего списка на значения из другого. Надеюсь понятно объяснил )
нет, v1 и _v ссылаются на один и тот же объект, который не затирается, а просто изменяется, потому что список это изменяемый тип данных, со строкой либо кортежем такой бы трюк не прокатил, потому что там бы в любом случае создавался новый объект, на который бы ссылался только _v
Спасибо за Ваши уроки. Вы очень хорошо объясняете. Скажите пожалуйста, Сергей, а вы планируете урок по асинхронному программированию на пайтон?
Спасибо! На очереди DRF и машинное обучение
Спасибо! Гениально!
Думаю стоило упомянуть хотя-бы разок, что используя конструкцию среза вы получаете поверхностную копию списка, для полного копирования (например когда у вас список объектов) можно использовать deepcopy из библиотеки copy.
зачем, не в этом смысл урока и элементы списка неизменяемые переданы.
Уже вроде и с ООП разобрался, декораторы, генераторы, на джанго и DRF написал несколько приложений, но вот менеджер контекста все равно вызывает у меня трудности. 😅
Спасибо автору, лучший канал как по мне
Большое спасибо. Очень интересно и полезно. Применю.
Два дня не мог понять, почему при изменении "self.__v" меняется сам "v1", ведь нигде нет кода типа: "v1 = self.__v[:]".
В итоге до меня дошло, что "v1", "v", "self.__v" это все ссылки на один и тот же список, у них у всех один и тот же id, и меняя один мы меняем все остальные.
Самое непонятное видео за всё время ООП) Мой мозг не понимает ничего
спасибо! интересный урок
Ура! В питоне тоже есть идиомы владения🥴 безопасность повышаем🤪
все понял, кром того как это работает: self.__v[:] = self.__temp
Переменная экземпляра класса DefendVector self.__v ссылается на тот же объект что и глобальная переменная v1(т.е. на лист [1, 2, 3]). И для того, чтобы не менять ссылки(т.е. переменные) автор меняет значения списка(в данном случае наш объект). Если две переменные ссылаются на один и тот же объект, это значит, что они зависят друг от друга, измени в одной переменной значение списка, оно также поменяется и в другой переменной, которая ссылается на тот же самый объект. Если бы автор записал так self.__v = self.__temp, это значило бы, что переменная __v ссылается уже абсолютно на другой объект, в данном случае это введет к тому, что переменная v1, осталась бы без изменений, так как __v это уже независимый объект, и v1 никаким образом не подтянет тех изменений, которые произошли в переменной __v.
Тоже не понял этот момент, сейчас постараюсь разобраться
Сергей, а можете поподробнее сказать по поводу return False в exit
В ООП существуют различные исключения, которые генерируются командой raise. Когда оно появлявляется, то программа должна либо обработать его, либо оно будет подниматься до точки старта программы. Если и там не обработается, то программа завершит свою работу.
@@selfedu_rus Спасибо!
подскажи пожалуйста не могу врубиться) то что мы делаем в def __enter__ когда копируем список через self.__temp = self.__v[:] понятно. а то что мы делаем в def __exit__ когда обратно копируем уже измененный список self.__v[:] = self.__temp в self.__v. что тут делает [:] непонятно(
Мы модифицируем исходный список путем присваивания срезу новых значений. Погугли.
@@artbog спасиб, я гуглил) но врубился только после твоей подсказки) если синтаксис b = a[:] то мы копируем все значения из одного списка и в другой (создается новые объект). Но если мы делаем так a[:] = b, том мы возвращаем срезом ту часть списка которую хотим заменить, новым списком, заменяем ее значениями на значения списка "b", а остальные оставляем, при этом ссылка на объект "a" остается неизменной.
@@ДмитрийСмирнов-щ4с все верно 👍
@@ДмитрийСмирнов-щ4с а есть разница между a[:] = b и a = b? Ведь в данном случае срезом является весь объект, мы ничего не обрезали.
@@genghiskhan8835 я понимаю так: если мы делаем a = b, то в переменную a копируем ссылку на объект из переменной b. Но если мы делаем a[:] = b то переменная a смотрит на тот же объект что и раньше (на видео это список [1, 2, 3]) и меняются сами значения в этом списке, сама ссылка на объект остается неизменной. это нам как раз и нужно по задаче, чтобы в случае успешного изменения нужный нам объект менялся, в случае неуспешного оставался неизменным. Короче разница что если сделать a = b, то в примере на видео мы в конце будем вызывать print(v1) и объект на который ссылает переменная v1 никогда не будет меняться, хоть успешно все прошло хоть нет.
в UI библиотеке Gradio очень непонятное использование менеджера контекста
import gradio as gr
with gr.Blocks() as demo:
gr.Markdown("...")
with gr.Tab("Flip Text"):
gr.Markdown("...")
demo.launch()
Не понятно как это работает)
Вопрос на 7й минуте - когда мы создаём enter метод, присходит переприсваивание, и таким образом копируем объект, копирование поверхностное или глубокое?.. вообще в питоне при вот таком переприсваивании какое копирование происходит?..
в данном случае мы выполняем обычное копирование списка, т.е. если он будет иметь вложения, то возникнут проблемы, но это учебный пример и не усложнял
Спасибо большое !
предыдущий материал курса ООП зашел на ура. но в этой теме возникла какая-то каша.
1) на 2.50 Вы пишете заголовок слайда "Менеджер контекста (with)" и вначале говорите "ключевое слово with, то есть это и есть менеджер контекста". на том же слайде на 2.50 написано, что менеджер контекста идет после ключевого слова with. так что из этого все же менеджер контекста?
2) еще больше путаницы внес первый тест после видео. один из вариантов ответа "менеджер контекста образует свою локальную область видимости (подобно функциям, тело которых находится внутри локальной области видимости)". в видео же вы создаете менеджер контекста - класс DefenderVector, далее пользуетесь экземпляром этого класса как менеджером контекста. т.е. у менеджера контекста есть своя локальная область видимости, в которой при инициализации формируется переменная self.__v. тогда почему указанный вариант ответа в тесте неправильный? исходя из того, что этот вариант ответа не верный, стоит полагать все же что менеджер контекста это with? однако для примера создания менеджера контекста вы прописываете то, что идет ПОСЛЕ with.
3) допустим, менеджер контекста - это объект после with. тогда если мы пишем with open('file') as file менеджером контекста будет open()? но ведь это же стандартная функция питона, а не менеджер контекста.
Уважаемый Сергей, очень ценю Ваш труд, понимаю что материала много и грамотно его структурировать - не простая задача. в этот раз получилось как-то запутанно
Я, конечно, не могу говорить с точной уверенностью, но как я понимаю и знаю, контекстный менеджер это то, что идет после with, ибо контекстный менеджер это класс, который содержит два магических метода __enter__ и __exit__ , а ключевое слово with существует, для того чтобы в правильном порядке вызывать данные магические методы. И как вы заметили, функция open() является по факту классом, который как раз таки и имеет эти два метода
Подскажите пожалуйста, почему в методе exit обязательно надо использовать срез:
self.__v[:] = self. __temp
Если срез не использовать, то список v1 не меняется
Этот код меняет только содержимое объекта, в обратном случае self.__v = self. __temp переменной self.__v присваивается новый объект, который был создан в __temp. Оригинальный список v1 больше не изменяется, так как self.__v теперь указывает на другой объект, ссылки на v1 за пределами контекстного менеджера останутся прежними, и их содержимое не изменится.
Большое спасибо! Хотлеось бы более подробно узнать про остальные праметры в __exit__
Спасибо! Документацию никто не отменял ))
Сергей, спасибо большое за видео!
Я не особо понял момент на 7:35 с 11 строкой, почему там [:] у srlf.__v? Я не особо понимаю как это работает в данном случае, прошу объяснить этот момент)
Это база языка. Полный срез [:] для списков означает их копирование.
@@selfedu_rus я понимаю что это обозначает копирование, но я не понимаю почему это стоит у self.__v, а не у srlf.__temp. Мы же копируем __temp в __v
@@dkuz Внутри этой штуки:
with DefenerVector(v1) as dv:
мы должны работать с копией списка, т.к. если что то пойдет не так, иметь возможность его восстановить
@@selfedu_rus все, теперь понял. Спасибо большое за курс и за то, что отвечаете на комментарии, не смотря на то, что видео вышло больше года назад!
Сорри, но этот урок у вас вышел очень запутанным и непонятным
на самом деле нет, прост чуть знания подтяни в ООП и дандерах, там ничего страшного нет
Спасибо! Получается, что open это все таки не функция, а целый класс, где реализованы методы enter, exit, call? Т.е. мы можем в свой любой класс добавить функциональность менеджера контекста?
да в Python много что через классы сделано, например, type() тоже класс и даже метакласс, о чем подробнее дальше )
Нет, open это функция, которая возращает менеджер контекста. Вы можете сами сдеать подобную функцию:
class MyContext:
def __init__(self, v):
self.__v = v
def __enter__(self):
self.__tmp = self.__v[:]
return self.__tmp
def __exit__(self, *exc):
self.__v[:] = self.__tmp
return False
def give_context(v):
return MyContext(v)
a = [1, 2, 3]
b = [2, 2]
# b = [2, 2, 2]
with give_context(a) as v:
for i in range(len(v)):
v[i] += b[i]
print(a)
Спасибо за урок! Хочу задать вопрос, как вы выделяя несколько строк помещаете их все в комментарии (# перед всеми) или ставите перед всеми отступ (tab)? Просто когда я так делаю в pycharm, строки попросту заменяются. Это настраивается как - то? Заранее спасибо.
Ctrl + / (при англ раскладке клавиатуры)
табуляцию двигать ctrl + [, либо ctrl + ], но это для vs code, может в pycharm так же
@@ДімаКуріптяTab и Shift + Tab
Наверное первая тема которая до конца не ясна В частности все случаи с параметрами exit- но пока для работы достаточно и этих знаний
Я правильно понимаю, что именно слово with определяет порядок вызова и делает сам вызов методов __enter__, __exit__ ? потому как код dv = DefendVector(v1)... не работает, хотя методы в классе переопределены
да, менеджер контекста сам вызывает эти магические методы
👍👍👍👍👍👍👍
Для чего нужен менеджер контекста и где его применять?.. для безопасности кода и применять везде где только можно. Имхо. Потому как класс который создаёт объект и должен его уничтожать… особенно если вы работаете с ресурсами. Инициализация как захват ресурса
Ошибку поправьте или меня - имя переменной мен контекста полагаю должно быть fp, а не f… (2-я минута)
да, очевидная ошибка, за всем не уследишь, на мой взгляд настолько очевидно, что даже не менял
@@selfedu_rus зато ролик отличный, спасибо!
Круто! Вы где учились?
Спасибо! Просто давно программирую и преподаю в вузе (детали не спрашивайте, не люблю публичность)
@@selfedu_rus при этом фамилию свою сказали))
Добрый день! Спасибо большое за все Ваши уроки. Они очень полезны. Хотел спросить а по ООП в Python не планируется ли курс на Stepik?
пока не знаю, сейчас явно не до этого
Взял и купил курс от поколения, уперся в задачу и не могу решить. Посмотрел видеоурок от Балакирева - понял что делал не так. Покупка была ошибкой.
👍
👍