Подготовили PDF шпаргалку, которую можно распечатать и держать перед глазами, чтобы быстрее всё запомнить: to.digital/s/12-python-oneliners.pdf - цветная версия to.digital/s/12-python-oneliners-wb.pdf - чёрно-белая версия Мой курс «Хардкорная веб-разработка» - course.to.digital Вжух!
Относительно .split есть неточность: split() и split(" ") - не одно и то же. split() для разделения использует не только пробел, но и все whitespace символы, например, таб, а также последовательность таких символов рассматривается как один - сплитятся слова независимо от кол-ва пробелов между ними. split(" ") сплитит строго по одиночным пробелам
Нужно добавить, что копирование вида L2 = L[:] является поверхностным копированием, а не полным. Это значит, что если есть вложенные в список структуры, например: ещё один список или словарь - то могу возникнуть проблемы. В таких случаях нужно использовать функцию deepcopy из модуля copy.
Да для многих многосторонность читабельнее нежели вот то. Но не знаю, я как человек который боролся, в процессе обучения, за лучшие решения в Кодварс могу сказать этот код выглядит элегантным :)
Так то можно и целиком модули/скрипты/программы упихивать в одну строку, но имхо, читаемость кода значительно выше в большинстве случаев, когда кодер не поленился и написал в несколько строк каждое действие пошагово, а не запихнул миллион действий в одну строку, действия в которой выполняются теперь и не слева направо и не справа налево, а в порядке, индивидуальном для каждого случая. Что такое x * y * z понятно сразу, а редьюс от принципиально неименуемой функции и мапа с данными, которые хз какие они там придут вообще - это нифига без пузыря и не разберешься, нафига оно нужно тут
Так цель видео в первую очередь обучить этим фичам, а не научить пихать всё в одну строку. Всегда полезно знать, как можно сделать, чтобы применить часть знаний в нужном месте правильно.
Братан как же приятно тебя слушать, очень позитивный чувак. За пять лет от галер до крупных банков ни одного хорошего человека на сеньере не встретил. 90 процентов это пассивно-агрессивные, злые, но трусливые шавки нолайферы, которые в технологиях сами еле-еле разбираются. Братан, есть у тебя команда? Я бы с удовольствием поработал с тобой.
Крутое видео, подача как всегда на уровне! НО Думаю, нужно было бы добавить про: 1. * в разделе про распаковку 2. copy, deepcopy 3. прекрасное нововведение py3.8 - walrus operator 4. _ в роли улучшения читаемости кода, когда значение не нужно, т.е.: for _ in range(10): pass 5. _ в роли разделителя для больших чисел: for _ in range(1_000_000): pass *ну а вообще в таких случаях лучше писать 10**6 Спасибо за то, что ты делаешь Один из немногих качественных каналов в ру сегменте
16:56 только что проверил данный код. На самом деле, это обычный аналог copy.copy функции, которая копирует не объект полностью, а лишь его структуру. Т.е. в случае, если ваш список будет многоуровневым (список в списке), то при изменении внутреннего списка, эти изменения отразятся и на скопированном списке. Так что если нужно железобетонно скопировать список как полностью новый объект, то лучше воспользоваться функцией из модуля copy deepcopy.
Первый пример: А можно ведь и без .strip() обойтись, так как без параметров он убирает только whitespaces, а .split() по умолчанию с краёв их тоже уберёт. Т.е. для решения этой же задачи можно просто input().split()
эта история работает только пробельного разделителя, если ты сплитнешь по запятой строку вида a = ", asd , ggg, rrrr , f, j" то пробелы с краев никуда не денутся. поэтому лучше сразу привыкать всегда делать стрип после сплита.
Алексей, спасибо! Долго держал видео в закладках. В итоге, когда сейчас посмотрел, то всё уже знаю. Но, подача, как всегда, отличная. Спасибо ещё раз! Ждём новых подобных видео!
Спасибо Добрый человек. На степике прохожу 2 курс по пайтон поколение питон для продвинутых, на будущее присматриваю, чем продолжить. Увидел ваш курс. Добавил в закладочки. По строчным выражениям очень удобная штука, особенно циклы в них, в том числе вложенные.
Вместо последнего пункта напрашивается создать Интерфейс Group, от которого будут наследоваться AdminGroup, ManagerGroup и т.д. Они будут по разному определять метод process_request.Тогда вместо стринга можно в конструктор User передать Request через интерфейс
В последнем примере можно сделать декоратор который будет генерировать айтемы в этом словаре и навесить его на функции обработчики, а так же дополнительно можно сделать функцию которая будет резолвить это, может быть удобно если структура более сложная, со вложенными словарями
Смотрю уже в середине ролика и думаю, надо бы написать, чтобы снял про замену if_else на dict_get - а в конце финальный аккорд как раз об этом. Молодец! Крутой мануал для джунов - ведь на собесех постоянно спрашивают об этих фишках. Такой же ролик стоит снять про: @staticmethod @classmethod @dataclass про использование абстрактных классов про синглтоны про конечные автоматы или машины состояний
Ну довольно простые приемы, все их я уже знал, кроме последнего, но там можно логически додуматься, хорошо зная питон, однако материал клевый, подача супер, все быстро, наглядно, с объяснениями, супер!
Недавно вывел для себя такой однострочник. Допустим есть такая структура: dataset = [{'a': 1, 'b': 2}, {'a': 11, 'b': 12}, {'a': 21, 'b': 22}, {'a': 31, 'b': 32}] и например нужно взять `b`, где `a` == 21: b = next(item['b'] for item in dataset if item['a'] == 21)
Сразу зачесалось дополнить)) 3. читаемее mul вместо lambda, вообще лямбды стараюсь использовать по минимуму: from operator import mul volume = reduce(mul, map(int, input().strip().split()) 5. Вот функциональная часть в питоне порой подбешивает.. Хотел бы я написать вот так, но не выйдет: tuple(filter(str.startswith('A'), names)) Нужно дополнительно усложнять т.к. по простому объект не передать, а магию передачи уже забыл (есть что-то встроенное, но с ним выглядит насколько я помню хуже чем с лямбдой), потому часто проще и читаемее использовать comprehensions. 12. Смело как то) Я бы сделал так: def fallback(user, request): print(f'Not exists group provided: {user.group}') # logging.error is better group_to_process_method.get(user.group, fallback)(user, request)
Возможно стоило также рассказать помимо словарей конфигурации и о существовании ConfigParser'а, все-таки сохранять конфиги нужно также и в моменты "простаивания" программного продукта
Видос супер. Бомбезные штуки показаны. Даже знаю где можно в моих проектах это могло бы заменить мой говнокод. Я в python новичок и выглядит всё это очень понятно и внятно, во многом благодаря подаче автора. Выражаю большую благодарность за столь мощный подход к созданию контента.
Думаешь, если ты пишешь по другому, например, перебор в цикле вместо in то твой код уже говнокод? Эти фишки только для профи, которые фигачат на питоне по 8 часов в день и так забадываются, что быстреев одну строку написать, чем цикл или функции расписывать. А на самом деле классический вид и работает быстрее, и читается лучше. Сам иногда грешу всякими тернарниками и лямбдами, а потом мой код никто понять не может... ))
@@pythonofsky4545 нет, думаю если ты не знаешь синтаксические и общепринятые конструкции, то собираешь велосипед, у которого и педали крутить сложно и руль фиг пойми как работает и колёса в разные стороны крутятся. Ясно правило "Нормально делай - нормально будет", но иногда из-за не знания особенностей различных инструментов лепишь фиг пойми какую чушь. И я тоже за понятный код, но в некоторых моментах всё-таки стоит использовать лаконичные подходы, которые и читаются просто, если знать язык, и не загромождают код ненужной белибердой.
Лямбды выглядят чуждо для семантики языка. В шарпее с LINQ с этим всем гораздо лучше: 6:58 int volume(string input) => input.Split(' ').Select(int.Parse).Aggregate((a, b) => a * b); 12:34 List filter(string[] input, string prefix) => input.Where(o => o.StartsWith(prefix)).ToList(); В случае с in это .Contains(), аналогичные .All() и .Any() так же имеются. При том, что это всё просто extension methods по IEnumerable.
Такой код выглядит приятно для глаза и экономит место. Вот только читабельным он является только для того, кто знает эти фишки. Например, если бы я до этого видел увидел конструкцию [::-1] я бы во-первых не понял, что тут вообще происходит, а во-вторых засомневался бы - работает ли оно вообще? Спасибо за интересные фишки конечно, но я лучше потрачу 2-3 строчки кода и опишу последовательность действий в явном виде. Надеюсь мой неведомый потомок скажет мне спасибо :-)
Сразу лайк =) ну и... вкусовщина конечно, но вместо lambda x, y: x * y можно использовать operator.mul а по последнему имхо наглядней Enum ну и можно через f-строку красиво сделать, например если это методы класса - getattr(self, f"process_{user.group}_request")(user, request)
Знаешь, спасибо тебе Когда-то давно я просто смотрел твои видосы, ничего не понимал Потом через время начал учиться жабускрипт, и спустя пол года устроился Сейчас, спустя 8 месяцев работы, являюсь мидл фулстак разрабом, с зп в 200 рублей Недавно увидел первый лям, и задумался с чего все начиналось и твой видос с реки попал, и все сошлось Спасибо!!
Спасибо за хаки. Компрехеншны удобны. К обработке текста нужно привыкнуть. Например в R фильтрация идёт грепом: names = c('Хри', 'Аде', 'Тэя', 'Сте', 'Арх') grep("^А", names, value = TRUE) или конвейером: names %>% grep ("^А", ., value = TRUE) И в ифчиках/фильтрах есть булевый grepl(). Вот прям оч удобно.
Я заговнокодил первый вариант без дополнительных библиотек и чисто в одну строку)): for num in [input().split() for x in range(1)]:print(int(num[0])*int(num[1])*int(num[2]))
Конфигурационный словарь нужно будет согласовывать со списком типов пользователя. Этот вопрос будет решён если вместо строки использовать dataclass(name: str + process_request: Callable) как аргумент __init__ . В таком случае мы можем спрятать вызов process_request с user как аргумент внутри функции класса User.
21:00 функция all умеет удивить. Пустая коллекция -- это False, конечно же. Но не в этом случае. Это прикол из высшей математики, "парадокс одинокого француза": если в комнате нет ни одного человека, то можно утверждать, что ВСЕ люди, находящиеся в комнате -- французы. Или пингвины. Или что угодно. Вот такие грибы. Зачем понадобилось лепить такое в стандартную библиотеку, окутано глубоким хз. Это просто надо запомнить.
Пример, когда all() может вас подставить: all(( hasattr(my_object, "some_data"), my_object.some_data is not None )) all() будет проверять все условия, даже если одно из них уже точно ложное, поэтому если у my_object нет атрибута some_data, при проверке второго условия вас будет ждать AttributeError.
map принимает последовательность вторым аргументом, это ведь несовсем правда, map iterable принимает, это более широкий интерфейс, а sequence это более узкий интерфейс, он iterable (__iter__), sized(__len__) и container(__in__), iterable это может быть и генератор и сопрограмма (Coroutine) это я не поумничать пишу просто мне кажется важным различать ту самую утиную типизацию, где какой минимальный интерфейс необходим, ну и это помогает точно хинты писать, где что надо за материал, большое спасибо, очень полезно
print('Василий' if 'Василий' in ('Христофор','Василий') else '') Таким образом можно сократить условие и вывод до одной строчки.Блок else в данном случае обязательный (тут он просто выведет пустую строку если нашего имени не обнаружилось в кортеже)
Так в нормальных языках люди смотрят в спецификацию коллекции и обнаруживают у неё все необходимые функциональные методы filter, map, all, every... А в python перевернули всё с ног на голову, и поэтому чтобы узнать о существовании глобальных методов all, any, должно снизойти свыше.
Привет из 2024г. К обращению списка могу добавить, что нечасто нам нужен отдельный обращенный список. Гораздо чаще нам нужно обрабатывать исходный список с конца. Тут может помочь функция reversed. Она предоставляет итератор, по которому список просматривается с конца, и не копирует исходный итерируемый объект.
Лучано Ромальо в своей книге "python к вершинам мастерства" писал про то, что вместо функциональщины (map, reduce, lambda-функций) почти всегда можно воспользоваться генератором списка, кортежа или словаря, и это и есть pythonista-style))
Досмотрел до 13 минуты уже. Снова ты лезешь в функциональщину (используешь filter), вместо генератора. При этом сначала, ты всё таки написал генератор [name for name in names if name.startwith("A")]. Такой пример отработал только потому что функция startwith подразумевает работу со строкой. Тут легко запутаться. В питоне нельзя просто так взять и перебрать список со строками, т.к. обычный цикл начнёт идти по первой строке (т.к. это тоже последовательность) и на ней же и остановится. Я бы рекомендовал перебирать такие списки со строками используя генератор enumerate. Например: for index, string in enumerate(list_of_string): If ... In string: Do_something() Или в виде генератора списка: [Index, do_something(string) for index, string in enumerate(list_of_string)] Последний пример грубый, Яя так не делал давно, но точно знаю, что можно использовать генераторные выражения в list comptehensions))
Да все используют функциональщину, почти во всех больших взрослых проектах она есть, ибо удобно. А кто не умеет map читать, ну его проблемы, я считаю. Нет ничего нечитаемого в map(str.strip, strings), элементарная конструкция, и если сделать это в comprehension, то код не станет лучше
Про all есть нюанс. В случае перечисления через and проверка остановится, как только встретит первый False. В случае с all будут проверены все элементы. То есть перечисление через and хоть и не такое красивое, но более эффективное.
Кто-то смотрит и удивляется новым для себя возможностям, а я удивлялся все видео тому как легко ты справляешься с vim и каким образом вообще vim понимает до какого символа тебе нужно выделить текст?????!! Врыв мозга просто…
Все супер, в эффективности и читаемости не везде конечно соглашусь, но в целом большинство «приемчиков» достаточно хорошо упрощают читаемость кода. А будут ли какие-то более продвинутые темы?
Интересно псмотреть на покрытие юнит тестами при любви к однострочкам... И что-нибудь услышать про maintainability кода где в одну строку выполняется сразу несколько операций. Ты, наверное, сознательно опустил процесс валидации инпута в первом примере и любой еррор хендлинг. Вобщем, чёт я ожидал большего. Больше выглядит как студенческий код для фриланса нежели продакшн код с какого то нормального проекта или энтерпрайза.
интересно, но не стоит забывать, что пишем 1 раз, а читаем 100: Explicit is better than implicit. Simple is better than complex. Flat is better than nested. Sparse is better than dense. Readability counts.
Недавно открыл для себя встроенную функцию eval, с помощью которой последний пример можно уместить в одну строчку. Вот пример: eval(f"process_{client.group}_request(user, request)")
eval потенциально небезопасен - он выполняет произвольный код, надо очень сильно подумать, прежде чем использовать его. Того же эффекта можно добиться без eval, если речь о методах внутри класса: getattr(SomeClass, f'process_{user.group}_request')(user, request). Если речь не о методе класса, а именно о функции - можно достать её из locals(), docs.python.org/3/library/functions.html#locals Но у такого подхода с составлением строки, содержащей имя метода/функции, есть один минус - IDE не отрефачит такой код, если функция будет переименована
Спасибо за видео, хороший формат, давно искал такое. К сожалению, ничего нового для себя не увидел, хотелось бы чего то нового, может быть сложнее, или "спрятанного".
В теме про однострочные конструкции еще неплохо было бы упомянуть о "моржовом" присваивании := Тоже интересный "сахар", появившийся только в Python 3.8
К сплиту лепить стрип не надо, т.к. сплит уже убрал лишние пробелы. Такая конструкция может применяться в случае если мы в сплит передаем аргумент с конкретным разделителем. Срезы не изменяют список, т.е. конструкция список[::-1] просто возвращает список в обратном порядке, список при этом остался в первоначальном варианте. Для того чтобы развернуть список используется reverse().
Предостережение автору. Упрощая, слово group произносится как /груп/. Если произносить /гроуп/, получается слово grope с совсем другим значением, возможно нежелательным в образовательном видео
Привет! Большое спасибо за видео. Не так давно ты говорил, что там, где требуется быстродействие код пишется на Go или на C/C++. У меня вопрос: чистый C жив в веб-разработке?
Привет! Не могу сказать про C/С++, так как не слежу за ними. Думаю, что какие-то хардкорные вещи под нагрузку пишутся на С или C++, но в будущем Rust их вытеснит в таких нишах.
Крутяк, спасибо, собрание классных фишек в одном видео с простыми примерами. Я бы еще добавил насчет генераторов: my_list = (x for x in range(30000000)) my_list1 = [x for x in range(30000000)] Теперь, если обходить в цикле первую конструкцию, затраты по памяти составят 17 Мб, а если вторую, то больше 1 Гб
насколько я понимаю, в первом случае создаётся генератор, который генерирует цифры по ходу итерации, следовательно памяти много не нужно. А в случае генерации списка, в него заносится цифры на хранение которых нужна память,ну и при итерации в данном случае идёт перебор элементов списка
если попробовать обратиться к генератору и сказать ему допустим my_list[5], то он выбросит ошибку, так как генератор не знает, какое число там будет, до данного числа нужно итерироваться. А в случае my_list1[5] будет выдано число
Подготовили PDF шпаргалку, которую можно распечатать и держать перед глазами, чтобы быстрее всё запомнить:
to.digital/s/12-python-oneliners.pdf - цветная версия
to.digital/s/12-python-oneliners-wb.pdf - чёрно-белая версия
Мой курс «Хардкорная веб-разработка» - course.to.digital
Вжух!
19:28 Чувак, ударение в слове красивее поставил слегка неправильно. А так очень познавательный выпуск.
Красавчик ! но шпаргалка в формате txt честно не хватает )) !!!!
Относительно .split есть неточность: split() и split(" ") - не одно и то же. split() для разделения использует не только пробел, но и все whitespace символы, например, таб, а также последовательность таких символов рассматривается как один - сплитятся слова независимо от кол-ва пробелов между ними. split(" ") сплитит строго по одиночным пробелам
Результат то одинаковый?
@@Pafel0684 нет )
Насчёт множественных пробелов: split(' ') делает также
@@frand2158 нет
@@Pafel0684пример: "товар\tяблоко".split() = [товар, яблоко] та же строчка только теперь с split(" "), мы получим [товар\tяблоко]
Нужно добавить, что копирование
вида L2 = L[:] является поверхностным копированием, а не полным. Это значит, что если есть вложенные в список структуры, например: ещё один список или словарь - то могу возникнуть проблемы. В таких случаях нужно использовать функцию deepcopy из модуля copy.
мало того, такая штука будет корректно работать только с объектами которые поддерживают срезы
Полезный коммент. В питоне много шансов при обучении упустить историю с глубоким и поверхностным копированием.
Полностью согласен, тоже смотрел об этом подумал
а если вызвать метод copy() ?
@@AJIagguH Если взять L.copy() - это будет эквивалентно L[:]
Не, ну когда reduce добавили с лямбдой, уже усложнено для восприятия, лучше отдельной строкой это делать. Явное лучше неявного или как там в дзене...
Да для многих многосторонность читабельнее нежели вот то. Но не знаю, я как человек который боролся, в процессе обучения, за лучшие решения в Кодварс могу сказать этот код выглядит элегантным :)
Вместо лямбды с reduce:
from math import prod
volume = prod(map(int, input().strip().split()))
Так то можно и целиком модули/скрипты/программы упихивать в одну строку, но имхо, читаемость кода значительно выше в большинстве случаев, когда кодер не поленился и написал в несколько строк каждое действие пошагово, а не запихнул миллион действий в одну строку, действия в которой выполняются теперь и не слева направо и не справа налево, а в порядке, индивидуальном для каждого случая.
Что такое x * y * z понятно сразу, а редьюс от принципиально неименуемой функции и мапа с данными, которые хз какие они там придут вообще - это нифига без пузыря и не разберешься, нафига оно нужно тут
пиши машинный код, будет понятно
@HoroscopeVideo - Гороскоп на сегодня Единственный здравый комментарий. Без мата на его редьюс невозможно смотреть
Ну когда переменных 2-3 то конечно лучше не использовать reduce, но если их 30-40, то reduce смотрится уже привлекательнее
уроки Python бесплатно - ua-cam.com/video/TPFQkLlbs4o/v-deo.html
Так цель видео в первую очередь обучить этим фичам, а не научить пихать всё в одну строку. Всегда полезно знать, как можно сделать, чтобы применить часть знаний в нужном месте правильно.
Братан как же приятно тебя слушать, очень позитивный чувак. За пять лет от галер до крупных банков ни одного хорошего человека на сеньере не встретил. 90 процентов это пассивно-агрессивные, злые, но трусливые шавки нолайферы, которые в технологиях сами еле-еле разбираются. Братан, есть у тебя команда? Я бы с удовольствием поработал с тобой.
Крутое видео, подача как всегда на уровне!
НО
Думаю, нужно было бы добавить про:
1. * в разделе про распаковку
2. copy, deepcopy
3. прекрасное нововведение py3.8 - walrus operator
4. _ в роли улучшения читаемости кода, когда значение не нужно, т.е.:
for _ in range(10):
pass
5. _ в роли разделителя для больших чисел:
for _ in range(1_000_000):
pass
*ну а вообще в таких случаях лучше писать 10**6
Спасибо за то, что ты делаешь
Один из немногих качественных каналов в ру сегменте
py - python ?:)
Спасибо мне было очень полезно, 3-5 вообще не знала
еще можна 10e6, число после `e` - количество нулей
Из серии "хозяйке на заметку" - просто, легко, красиво. Приятно слушать человека, который знает, о чем говорит. Спасибо!
Хоть и всё изложенное использую, но с удовольствием посмотрел ролик, подача шикарная!)
11:30 Сеты это все же не массивы , а множества.
Спасибо за видео.
16:56 только что проверил данный код. На самом деле, это обычный аналог copy.copy функции, которая копирует не объект полностью, а лишь его структуру. Т.е. в случае, если ваш список будет многоуровневым (список в списке), то при изменении внутреннего списка, эти изменения отразятся и на скопированном списке.
Так что если нужно железобетонно скопировать список как полностью новый объект, то лучше воспользоваться функцией из модуля copy deepcopy.
+
Ну это понятно и так. Не зря же deepcopy придумали. А срезы как быстрый и элегантный способ работы со списками, кортежами.
Первый пример:
А можно ведь и без .strip() обойтись, так как без параметров он убирает только whitespaces, а .split() по умолчанию с краёв их тоже уберёт. Т.е. для решения этой же задачи можно просто input().split()
эта история работает только пробельного разделителя, если ты сплитнешь по запятой строку вида a = ", asd , ggg, rrrr , f, j" то пробелы с краев никуда не денутся. поэтому лучше сразу привыкать всегда делать стрип после сплита.
только сейчас понял как работает map, про reduce не знал, спс за видео, как всегда топ
Алексей, спасибо! Долго держал видео в закладках. В итоге, когда сейчас посмотрел, то всё уже знаю. Но, подача, как всегда, отличная. Спасибо ещё раз! Ждём новых подобных видео!
Спасибооо!
Задача-1. Длина, ширина, высота вводятся через пробел, вычислить объём.
print(eval(input().strip().replace(' ','*')))
или так
print((lambda l, w, h: int(l) * int(w) * int(h))(*input().split()))
💯 ТОП!🔥 Сделай пожалуйста PDF: было/ стало, чтобы все могли скачать и было всегда перед глазами.
Отличная мысль, сделаем!
8:20 попався джсер)
да вот задолбали они, не могли хотя бы синтаксис комментариев во всех ЯП сделать однородным:)
@@t0digital так в питоне комменты как в bash, он ведь с ним конкурировал изначально.
Спасибо Добрый человек. На степике прохожу 2 курс по пайтон поколение питон для продвинутых, на будущее присматриваю, чем продолжить. Увидел ваш курс. Добавил в закладочки. По строчным выражениям очень удобная штука, особенно циклы в них, в том числе вложенные.
Очень базовый и очень полезный видос. Спасибо автору, отличный формат, несешь добро людям )
Вместо последнего пункта напрашивается создать Интерфейс Group, от которого будут наследоваться AdminGroup, ManagerGroup и т.д. Они будут по разному определять метод process_request.Тогда вместо стринга можно в конструктор User передать Request через интерфейс
Декларативный способ подстановки функции супер! Решил проблему, над который давно думал. Спасибо, Алексей!
Видео хорошее, но важно помнить, что коротко, не всегда красиво и читаем. И автор говорит об этом. Не забывайте про pep8
В последнем примере можно сделать декоратор который будет генерировать айтемы в этом словаре и навесить его на функции обработчики, а так же дополнительно можно сделать функцию которая будет резолвить это, может быть удобно если структура более сложная, со вложенными словарями
Чудесно звучит🎉❤ а Когда же будет продолжение этой темы разговора😊
Очень полезное, а главное понятное видео, спасибо большое!
Смотрю уже в середине ролика и думаю, надо бы написать, чтобы снял про замену if_else на dict_get - а в конце финальный аккорд как раз об этом. Молодец! Крутой мануал для джунов - ведь на собесех постоянно спрашивают об этих фишках.
Такой же ролик стоит снять про:
@staticmethod
@classmethod
@dataclass
про использование абстрактных классов
про синглтоны
про конечные автоматы или машины состояний
а ещё очень крутая штука это @context. Ее как раз используют в машине состояний , но и не только
Классный урок!
Круто было бы послушать про протоколы!
уроки Python бесплатно - ua-cam.com/video/TPFQkLlbs4o/v-deo.html
Ну довольно простые приемы, все их я уже знал, кроме последнего, но там можно логически додуматься, хорошо зная питон, однако материал клевый, подача супер, все быстро, наглядно, с объяснениями, супер!
16:20 Кажется мне, что list(numbers) более читаемо, чем нецелево использованный слайс. И с разворотом то же самое -- есть reversed(). А вообще норм!
Слайсы популярны и используются повсеместно, с их понимаем проблем возникнуть не должно
Очень доходчиво и познавательно! Спасибо!
Недавно вывел для себя такой однострочник.
Допустим есть такая структура:
dataset = [{'a': 1, 'b': 2}, {'a': 11, 'b': 12}, {'a': 21, 'b': 22}, {'a': 31, 'b': 32}]
и например нужно взять `b`, где `a` == 21:
b = next(item['b'] for item in dataset if item['a'] == 21)
Сразу зачесалось дополнить))
3. читаемее mul вместо lambda, вообще лямбды стараюсь использовать по минимуму:
from operator import mul
volume = reduce(mul, map(int, input().strip().split())
5. Вот функциональная часть в питоне порой подбешивает.. Хотел бы я написать вот так, но не выйдет:
tuple(filter(str.startswith('A'), names))
Нужно дополнительно усложнять т.к. по простому объект не передать, а магию передачи уже забыл (есть что-то встроенное, но с ним выглядит насколько я помню хуже чем с лямбдой), потому часто проще и читаемее использовать comprehensions.
12. Смело как то) Я бы сделал так:
def fallback(user, request):
print(f'Not exists group provided: {user.group}') # logging.error is better
group_to_process_method.get(user.group, fallback)(user, request)
Коротко, ясно, без воды 👍
Возможно стоило также рассказать помимо словарей конфигурации и о существовании ConfigParser'а, все-таки сохранять конфиги нужно также и в моменты "простаивания" программного продукта
Видос супер. Бомбезные штуки показаны. Даже знаю где можно в моих проектах это могло бы заменить мой говнокод. Я в python новичок и выглядит всё это очень понятно и внятно, во многом благодаря подаче автора. Выражаю большую благодарность за столь мощный подход к созданию контента.
Думаешь, если ты пишешь по другому, например, перебор в цикле вместо in то твой код уже говнокод? Эти фишки только для профи, которые фигачат на питоне по 8 часов в день и так забадываются, что быстреев одну строку написать, чем цикл или функции расписывать. А на самом деле классический вид и работает быстрее, и читается лучше. Сам иногда грешу всякими тернарниками и лямбдами, а потом мой код никто понять не может... ))
@@pythonofsky4545 нет, думаю если ты не знаешь синтаксические и общепринятые конструкции, то собираешь велосипед, у которого и педали крутить сложно и руль фиг пойми как работает и колёса в разные стороны крутятся. Ясно правило "Нормально делай - нормально будет", но иногда из-за не знания особенностей различных инструментов лепишь фиг пойми какую чушь. И я тоже за понятный код, но в некоторых моментах всё-таки стоит использовать лаконичные подходы, которые и читаются просто, если знать язык, и не загромождают код ненужной белибердой.
Вопрос не по теме - а как вам картинка:)?
и звук ничо. Новая камера?
Wow 😍
Пожалуйста, делай отступы когда показываешь IDE. Из-за элементов интерфейса ютуба не видно код
круто все!
@@m_kovalenko отступы от краёв экрана, чтобы код не прилипал к краям экрана?
Лямбды выглядят чуждо для семантики языка. В шарпее с LINQ с этим всем гораздо лучше:
6:58 int volume(string input) => input.Split(' ').Select(int.Parse).Aggregate((a, b) => a * b);
12:34 List filter(string[] input, string prefix) => input.Where(o => o.StartsWith(prefix)).ToList();
В случае с in это .Contains(), аналогичные .All() и .Any() так же имеются.
При том, что это всё просто extension methods по IEnumerable.
Супер подходы, почти все использую. Спасибо!
В последнем примере с условиями думал нововведение switch и case сейчас покажешь,ан нет, на деле другое исполнение донес :) спасибо, не знал
Он же вроде в 3.10, а тут 3.9 =)
вообще не вижу какой то пользы от match,
передаёшь функции объект, а далее кейсы перехватывают.Всё то же самое можно реализовать условиями.
@@АлексейПротасов-п6э если у тебя более одного elif, то ты движешься куда-то не туда)
@@andreiosipov2766 это откуда ты такое взял что elif нельзя употреблять более раза?другое дело если else более раза
@@АлексейПротасов-п6э ты профессиональный разработчик? Работаешь с другими людьми, проходишь код-ревью?
Супер полезно! №8 и №11 сразу забрал в свой скрипт. Знал, что как-то лаконичнее можно, но не знал как.
Такой код выглядит приятно для глаза и экономит место. Вот только читабельным он является только для того, кто знает эти фишки. Например, если бы я до этого видел увидел конструкцию [::-1] я бы во-первых не понял, что тут вообще происходит, а во-вторых засомневался бы - работает ли оно вообще? Спасибо за интересные фишки конечно, но я лучше потрачу 2-3 строчки кода и опишу последовательность действий в явном виде. Надеюсь мой неведомый потомок скажет мне спасибо :-)
Сразу лайк =) ну и...
вкусовщина конечно, но вместо lambda x, y: x * y можно использовать operator.mul
а по последнему имхо наглядней Enum ну и можно через f-строку красиво сделать, например если это методы класса - getattr(self, f"process_{user.group}_request")(user, request)
уроки Python бесплатно - ua-cam.com/video/TPFQkLlbs4o/v-deo.html
Спасибо за конфигурационный словарь!
Очень хорошая и понятная подача материала, спасибо! Можете сделать видео о Django signals?
Спасибо! Очень полезно и понятно!
Алексей, спасибо за видео!
Огромное спасибо за работу, очень полезный видос🤝
Знаешь, спасибо тебе
Когда-то давно я просто смотрел твои видосы, ничего не понимал
Потом через время начал учиться жабускрипт, и спустя пол года устроился
Сейчас, спустя 8 месяцев работы, являюсь мидл фулстак разрабом, с зп в 200 рублей
Недавно увидел первый лям, и задумался с чего все начиналось и твой видос с реки попал, и все сошлось
Спасибо!!
Update: плюс ко всему мне 19)
Спасибо за хаки. Компрехеншны удобны. К обработке текста нужно привыкнуть.
Например в R фильтрация идёт грепом:
names = c('Хри', 'Аде', 'Тэя', 'Сте', 'Арх')
grep("^А", names, value = TRUE)
или конвейером:
names %>% grep ("^А", ., value = TRUE)
И в ифчиках/фильтрах есть булевый grepl(). Вот прям оч удобно.
Я заговнокодил первый вариант без дополнительных библиотек и чисто в одну строку)):
for num in [input().split() for x in range(1)]:print(int(num[0])*int(num[1])*int(num[2]))
Конфигурационный словарь нужно будет согласовывать со списком типов пользователя. Этот вопрос будет решён если вместо строки использовать dataclass(name: str + process_request: Callable) как аргумент __init__ . В таком случае мы можем спрятать вызов process_request с user как аргумент внутри функции класса User.
Опять таки знаю об этом я только благодаря твои предыдущим роликам
21:00 функция all умеет удивить. Пустая коллекция -- это False, конечно же. Но не в этом случае. Это прикол из высшей математики, "парадокс одинокого француза": если в комнате нет ни одного человека, то можно утверждать, что ВСЕ люди, находящиеся в комнате -- французы. Или пингвины. Или что угодно. Вот такие грибы. Зачем понадобилось лепить такое в стандартную библиотеку, окутано глубоким хз. Это просто надо запомнить.
И правда, но не логично как-то..
24:20 - гораздо эффективнее в таких случаях прибегнуть к полиморфизму.
Спасибо за видео!
Крутая рубрика. Оч крутая. Такого бы по чаще.
Пример, когда all() может вас подставить:
all((
hasattr(my_object, "some_data"),
my_object.some_data is not None
))
all() будет проверять все условия, даже если одно из них уже точно ложное, поэтому если у my_object нет атрибута some_data, при проверке второго условия вас будет ждать AttributeError.
map принимает последовательность вторым аргументом, это ведь несовсем правда, map iterable принимает, это более широкий интерфейс, а sequence это более узкий интерфейс, он iterable (__iter__), sized(__len__) и container(__in__), iterable это может быть и генератор и сопрограмма (Coroutine)
это я не поумничать пишу просто мне кажется важным различать ту самую утиную типизацию, где какой минимальный интерфейс необходим, ну и это помогает точно хинты писать, где что надо
за материал, большое спасибо, очень полезно
многое знал, но пару фишек утащу, спасибо)
print('Василий' if 'Василий' in ('Христофор','Василий') else '')
Таким образом можно сократить условие и вывод до одной строчки.Блок else в данном случае обязательный (тут он просто выведет пустую строку если нашего имени не обнаружилось в кортеже)
Вот таких видосов бы больше
Первая задача в одну строку))
print(*[x * y * z for x, y, z in [map(int, input().split())]])
То чувство что сначала сам решал задание а потом смотрел пример, почти все аналогично сделал🤔
Спасибо! Классный туториал получился!
Думал, что все уже знаю, но узнал про any и all только сейчас, спасибо за видос
Так в нормальных языках люди смотрят в спецификацию коллекции и обнаруживают у неё все необходимые функциональные методы filter, map, all, every... А в python перевернули всё с ног на голову, и поэтому чтобы узнать о существовании глобальных методов all, any, должно снизойти свыше.
Очень круто, очень полезно. Спасибо 👍 большое
Как вы красиво все объясняете 😌😃
Отличное видео, можно сделать серию таких?
Очень спасибо за формат таких видео!!
Привет из 2024г.
К обращению списка могу добавить, что нечасто нам нужен отдельный обращенный список. Гораздо чаще нам нужно обрабатывать исходный список с конца. Тут может помочь функция reversed. Она предоставляет итератор, по которому список просматривается с конца, и не копирует исходный итерируемый объект.
Отличный урок! Респект!
Интересное видео, особенно для того, кто только знакомится с python
Мегаполезная подборка. Огромнейшее спасибо!
Очень полезное видео, спасибо!
О теме с конфигурацией: кроме простой и pythonic конструкции мы также получим сложность O(1), вместо O(n)(при реализации c кучей elif).
уроки Python бесплатно - ua-cam.com/video/TPFQkLlbs4o/v-deo.html
Лучано Ромальо в своей книге "python к вершинам мастерства" писал про то, что вместо функциональщины (map, reduce, lambda-функций) почти всегда можно воспользоваться генератором списка, кортежа или словаря, и это и есть pythonista-style))
Досмотрел до 13 минуты уже. Снова ты лезешь в функциональщину (используешь filter), вместо генератора.
При этом сначала, ты всё таки написал генератор [name for name in names if name.startwith("A")]. Такой пример отработал только потому что функция startwith подразумевает работу со строкой. Тут легко запутаться. В питоне нельзя просто так взять и перебрать список со строками, т.к. обычный цикл начнёт идти по первой строке (т.к. это тоже последовательность) и на ней же и остановится. Я бы рекомендовал перебирать такие списки со строками используя генератор enumerate. Например:
for index, string in enumerate(list_of_string):
If ... In string:
Do_something()
Или в виде генератора списка:
[Index, do_something(string) for index, string in enumerate(list_of_string)]
Последний пример грубый, Яя так не делал давно, но точно знаю, что можно использовать генераторные выражения в list comptehensions))
Да все используют функциональщину, почти во всех больших взрослых проектах она есть, ибо удобно. А кто не умеет map читать, ну его проблемы, я считаю. Нет ничего нечитаемого в map(str.strip, strings), элементарная конструкция, и если сделать это в comprehension, то код не станет лучше
list comps, dict comp, gen exp это убойные инструменты питониста.
В сочетании с тернарным оператором вообще на глушняк :)
Про all есть нюанс. В случае перечисления через and проверка остановится, как только встретит первый False. В случае с all будут проверены все элементы. То есть перечисление через and хоть и не такое красивое, но более эффективное.
тут дело не в all.
all тоже не будет все элементы проверять, если это не нужно:
all((print(i) or i
Хорошее видео, спасибо.
Так глядишь, мне Пайтон зайдет и начну его использовать.
Много от Перл там вижу. Не знаю что раньше появилось.
Кто-то смотрит и удивляется новым для себя возможностям, а я удивлялся все видео тому как легко ты справляешься с vim и каким образом вообще vim понимает до какого символа тебе нужно выделить текст?????!! Врыв мозга просто…
так и знал что будет генератор списков, гениальная штука в питоне
Спасибо за all, any. ))
Спасибо, видео "пушка". А что за книга была на столе в этом видео?
Все супер, в эффективности и читаемости не везде конечно соглашусь, но в целом большинство «приемчиков» достаточно хорошо упрощают читаемость кода.
А будут ли какие-то более продвинутые темы?
Интересно псмотреть на покрытие юнит тестами при любви к однострочкам... И что-нибудь услышать про maintainability кода где в одну строку выполняется сразу несколько операций. Ты, наверное, сознательно опустил процесс валидации инпута в первом примере и любой еррор хендлинг. Вобщем, чёт я ожидал большего. Больше выглядит как студенческий код для фриланса нежели продакшн код с какого то нормального проекта или энтерпрайза.
Вот это - нечитаемо:
numbers = map(int, input().split())
А вот так - песня:
input_string = input()
input_word = input.split()
first_word = input_elements[0]
second_word = input_elements[1]
first_number = int(first_word)
second_number = int(second_word)
numbers = (first_number, second_number)
Ну ок:)
Алексей, благодарю += 1000 !!
интересно, но не стоит забывать, что пишем 1 раз, а читаем 100:
Explicit is better than implicit.
Simple is better than complex.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Ничего из перечисленного этот код не нарушает
numbers = map(int, strings_iterable)
крутое видео, классно понимать, что о мапе я узнал раньше (вчера)
Я бы еще добавил return + тернарный оператор, тоже моЩная конструкция
да! И что-то в духе:
value = variable1 or variable2
Cпасибо! Очень полезно и наглядно!
Большинство я уже знаю, но все таки, довольно много интересного узнал. Классно! А все таки... когда будет Go...?
Возможно будет раст вместо го:)
@@t0digital А почему? Гошка же лучше для веба :O
Пока не сложил для себя однозначного мнения по этому поводу. Go проще, это факт, но простота это не всегда лучше
@@t0digital вау раст! Слышал много хорошего, было бы интересно
вот и мне интересно, изучаю
Недавно открыл для себя встроенную функцию eval, с помощью которой последний пример можно уместить в одну строчку. Вот пример: eval(f"process_{client.group}_request(user, request)")
eval потенциально небезопасен - он выполняет произвольный код, надо очень сильно подумать, прежде чем использовать его. Того же эффекта можно добиться без eval, если речь о методах внутри класса: getattr(SomeClass, f'process_{user.group}_request')(user, request). Если речь не о методе класса, а именно о функции - можно достать её из locals(), docs.python.org/3/library/functions.html#locals
Но у такого подхода с составлением строки, содержащей имя метода/функции, есть один минус - IDE не отрефачит такой код, если функция будет переименована
@@t0digital Спасибо, раньше об этом как-то не задумывался, но и самой функцией (к счастью) раньше не пользовался.
Здорово? Здорово, дорогие друзья!!!
Таки да!
@@t0digital большое спасибо за контент!) все супер!
Спасибо за видео, хороший формат, давно искал такое. К сожалению, ничего нового для себя не увидел, хотелось бы чего то нового, может быть сложнее, или "спрятанного".
С объёмом можно вообще так написать
print(*[x*y*z for x, y, z in [map(int, input().split())]])
В теме про однострочные конструкции еще неплохо было бы упомянуть о "моржовом" присваивании :=
Тоже интересный "сахар", появившийся только в Python 3.8
Фуфуфу, непитонично
@@daninspace9009 Упомянутый в видео reduce - гораздо непитоничнее моржа)
@@VadimKochkarev ну смотря как применять)
К сплиту лепить стрип не надо, т.к. сплит уже убрал лишние пробелы. Такая конструкция может применяться в случае если мы в сплит передаем аргумент с конкретным разделителем.
Срезы не изменяют список, т.е. конструкция список[::-1] просто возвращает список в обратном порядке, список при этом остался в первоначальном варианте. Для того чтобы развернуть список используется reverse().
Предостережение автору. Упрощая, слово group произносится как /груп/. Если произносить /гроуп/, получается слово grope с совсем другим значением, возможно нежелательным в образовательном видео
Привет! Большое спасибо за видео. Не так давно ты говорил, что там, где требуется быстродействие код пишется на Go или на C/C++. У меня вопрос: чистый C жив в веб-разработке?
Привет! Не могу сказать про C/С++, так как не слежу за ними. Думаю, что какие-то хардкорные вещи под нагрузку пишутся на С или C++, но в будущем Rust их вытеснит в таких нишах.
интересно, а вытеснит ли Rust парочку C/C++ совсем? (для новых проектов, исключая имеющееся наследие)
Прямо Кунг-Фу - Python!!! 😀🤸♂️👍
Крутяк, спасибо, собрание классных фишек в одном видео с простыми примерами.
Я бы еще добавил насчет генераторов:
my_list = (x for x in range(30000000))
my_list1 = [x for x in range(30000000)]
Теперь, если обходить в цикле первую конструкцию, затраты по памяти составят 17 Мб, а если вторую, то больше 1 Гб
А если обходить итератор?
Так он сказал в видео, что кортежи эффективнее по памяти и нужно их использовать, везде где не требуется, дальнейшее изменение данных
насколько я понимаю, в первом случае создаётся генератор, который генерирует цифры по ходу итерации, следовательно памяти много не нужно. А в случае генерации списка, в него заносится цифры на хранение которых нужна память,ну и при итерации в данном случае идёт перебор элементов списка
если попробовать обратиться к генератору и сказать ему допустим my_list[5], то он выбросит ошибку, так как генератор не знает, какое число там будет, до данного числа нужно итерироваться. А в случае my_list1[5] будет выдано число
мои познания могут быть не совершенны, так что сорян если что :)
18:40 - в данном случае name не напечатался потому что ожидается ещё один