TGTGInsighttelegram intelligenceLIVE / telegram public index
Назад кон каналите
Python Заметки avatar

TGINSIGHT CHAT

Python Заметки

@pythonotes

Education

Интересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop

Претплатници2,220Тековни претплатници
Следени објави384Број на индексирани објави
Неодамнешен опфат7,999Збир на неодамнешни прегледи
Неодамнешни објави

Неодамнешни објави

Ознака: #tricks · 178 објави

当前筛选 #tricks清除筛选

Срез это довольно удобная штука для получения определённого диапазона элементов из списка. Но срезы не так просты как кажется, их можно использовать и для изменения оригинального списка так же как мы это делаем просто по индексу. Для примера возьмем простой список ls = [1, 2, 3, 4, 6] И поехали! >>> ls[-1] = 5 [1, 2, 3, 4, 5] Обычное изменение по индексу. >>> ls[2:4] [3, 4] Обычный срез который создаёт новый список на основе старого. >>> ls[::-1] [5, 4, 3, 2, 1] Реверс списка, тоже создаёт новый. Оригинальный список остался без изменений. Воспользуемся оператором присвоения: >>> ls[2:4] = [7, 8] [1, 2, 7, 8, 5] Заменили диапазон элементов в оригинальном списке. >>> ls[4:] = [0, 0, 0, 0] [1, 2, 7, 8, 0, 0, 0, 0] Указав диапазон сверх имеющегося мы расширили список по аналогии с методом extend(), но при этом еще и немного захватили конец списка. Всё это в одно действие! >>> ls[:0] = [9, 8, 7] [9, 8, 7, 1, 2, 7, 8, 0, 0, 0, 0] Добавили элементы в начало >>> del ls[-4:] [9, 8, 7, 1, 2, 7, 8] Удалили часть элементов списка >>> ls[1:3] = [] [9, 1, 2, 7, 8] Еще один способ удалить элементы >>> ls[:] = [] А этим способом можно пользоваться для очистки списка в Python2, в котором еще не было метода clear(). Кажется мы "потратили" весь наш список))) Сделаем новый и продолжим. >>> ls = [1, 2, 3, 4, 5, 6] >>> ls[::2] = [7,8,9] [7, 2, 8, 4, 9, 6] И конечно же мы можем использовать шаг в срезе, но тут требуется соблюдать количество подаваемых элементов. Заменять элементы с каким-то шагом можно, а добавлять нельзя. s = slice(3, 4) Как было показано ранее, срез можно сохранять как переменную и использовать в дальнейших манипуляциях >>> ls[s] = [0]*5 [7, 2, 8, 0, 0, 0, 0, 0, 9, 6] Заменили один элемент на несколько элементов, расширив исходный список из центра. И напоследок. Следующие два действия равнозначны и дадут одинаковый результат — полная замена списка. >>> ls[:] = [1,2,3,4] >>> ls = [1,2,3,4] #tricks

558 views

Hashtags

Наверняка вы часто используете генераторы списков (List Comprehension). Я тоже, даже порой злоупотребляю ими) Но что поделать, если они такие удобные! Давайте разберёмся как работают составные итерации в генераторе списка. Для начала посмотрим простой вид. >>> array = [1, 2, 3, 4] >>> [x for x in array] Этот код просто делает копию списка. Добавляем некоторое выражение: >>> [x*2 for x in array] Этот генератор создаёт новый список элементы которого в 2 раза больше чем в оригинальном списке. Добавим условие: >>> [x*2 for x in array if x%2] Предыдущему примеру добавили фильтр, который проходят только нечётные числа. В целом, я бы советовал на этом и остановиться. Не нужно усложнять простое! Мы можем итерировать в генераторе сразу два списка так, чтобы каждый элемент одного списка повстречался с каждым элементом из другого. >>> array1 = [1, 2, 3] >>> array2 = [4, 5, 6] >>> print([f'{i}-{j}' for i in array1 for j in array2]) ['1-4', '1-5', '1-6', '2-4', '2-5', '2-6', '3-4', '3-5', '3-6'] Давайте обозначу каждый цикл условными скобками чтобы было понятней (синтаксически это неверно). [f'{i}-{j}' (for i in array1) (for j in array2)] Можем добавить условие и сюда? Можем! >>> print([f'{i}-{j}' (for i in array1 if i >= 2) (for j in array2 if j < 5)]) ['2-4', '3-4'] При этом во второй итерации мы можем использовать переменную из первой >>> array = [(1, 2, 3), (4, 5, 6)] >>> new = [y for x in array for y in x] Кстати, мы разложили вложенные кортежи в один плоский список. Можем ли мы использовать больше двух итераций? Да хоть десять! >>> a1 = [9, 2, 4, 5] >>> a2 = [4, 5, 9, 1] >>> a3 = [5, 9, 3, 0] >>> match = [x for x in a1 for y in a2 for z in a3 if x == y and x == z] [9, 5] Нашли числа которые встречаются во всех списках. Можно еще сложней? Конечно, Python довольно многое позволяет делать. Но, как говорят про Python: если ЭТО можно сделать то еще не значит что ЭТО нужно делать. #tricks

580 views

Hashtags

В прошлом посте мы получали полное имя метода. В атрибут ˍˍqualnameˍˍ записано имя только до класса, к которому метод принадлежит. Как быть если нужно полное имя с модулем, а мы имеем только объект метода без инстанса или ссылки на класс? func = get_my_method() В результате этого псведо-выражения мы имеем только сам метод класса. Есть ли в нём информация к какому классу он принадлежит? Конечно есть, это атрибут ˍˍselfˍˍ. Он ссылается на инстанс. А оттуда, как не трудно догадаться, можно получить и ссылку на класс через атрибут ˍˍclassˍˍ: cls = func.__self__.__class__ итого полное имя будет выглядеть так full_name = '.'.join([ func.__self__.__class__.__module__, func.__qualname__] ) #tricks

574 views

Hashtags

Објавено 27 апр.

Ранее я делал серию постов про битовые операторы. Вот вам ещё один наглядный пример как это используется в Python в модуле re. Чтобы указать флаг для компилятора нам надо указать его после передаваемой строки. Например, добавляем флаг для игнорирования переноса строки. pattern = re.compile(r"(\w+)+") words = pattern.search(text, re.DOTALL) А как указать несколько флагов? Ведь явно будут ситуации когда нам потребуется больше одного. Кто читал посты по битовые операторы уже понял как. pattern.search(text, re.DOTALL | re.VERBOSE) А теперь смотрим исходники, что находится в этих атрибутах? Не удивительно, степени двойки. Почему? Потому что каждое следующее значение это сдвиг единицы влево. >>> for n in [1, 2, 4, 8, 16, 32, 64, 128, 256]: >>> print(bin(n)) 0b1 0b10 0b100 0b1000 0b10000 0b100000 0b1000000 0b10000000 0b100000000 Чтобы было понятней, давайте напишем тоже самое но иначе, добавим ведущие нули: 000000001 000000010 000000100 000001000 000010000 000100000 001000000 010000000 100000000 Не понятно что тут происходит? Читай три поста про битовые операторы начиная с этого ➡️https://t.me/pythonotes/45 В общем, это пример применения побитовых операций в самом Python. Теперь вы знаете Python еще немного лучше) #tricks#regex#libs

710 views

Објавено 25 апр.

Хотите оформить свои CLI скрипты красивым прогрессбаром? Стоит посмотреть на библиотеку progress. Она даёт возможность создавать красивые прогрессбары легко и быстро. Но что если не хочется добавлять лишнюю зависимость только ради одной бегущей полоски? Создать свою функцию с подобным функционалом — не проблема! Вот базовый набросок: import time for i in range(0, 100+1, 4): time.sleep(0.1) print('\r{:>3}% [{}{}]'.format(i, "#"*i, '-'*(100-i)), end='') print() Запустите код в интерактиве и увидите что работает не хуже. Вся хитрость в отсутствии переноса на новую строку в конце строки и в символе "\r" — возврат "каретки" (читай "курсора") в начало строки. После чего мы перезаписываем предыдущую строку. Главное в самом конце не забыть обычный print() чтобы перейти на новую строку. Расширенный вариант в виде контекст менеджера. 🌎 #libs#tricks

687 views

Hashtags

Објавено 21 апр.

Регулярные выражения иногда могут быть просто монструозными. Выглядеть это может крайне запутанно. Сами регэкспы и без того история непростая, а когда это длинный паттерн на несколько десятков знаков, разобрать там что-либо становится не просто. Но на помощь приходит Python и его стремление сделать нашу жизнь проще! В функциях регулярок можно после паттерна указывать флаги, один из которых позволяет писать паттерны более свободно. А именно, добавлять пробелы и переносы, которые будут игнорированы. В результате мы можем разбить паттерн на строки и добавить комментов. Чтобы это сработало нужно добавить флаг re.VERBOSE. Пробелы в паттерне теперь следует указывать явно спец символами. Согласитесь, что даже с именованными группами а таком виде регэкспа выглядит вполне сносно 😉. #tricks#regex

721 views

Објавено 17 апр.

Помните пример с неудачной вставкой комментария? x = 1 + \ # comment 2 x = 1 + \ # comment 2 Я говорил что так делать не стоит, так как вызывает ошибку. Но я же скажу как эту ошибку поправить! И это просто (((СКОБОЧКИ))) 😎! x = (1 + # comment 2) x = (1 + # comment 2) Теперь интерпретатор сообразит что к чему. Кстати, они же помогают избежать символа "\" в других случаях Без скобок from Qt.QtWidgets import QPushButton, QLabel, \ QTextEdit, QListWidget Со скобками from Qt.QtWidgets import (QPushButton, QLabel, # здесь можно вставить комментарий QTextEdit, QListWidget) Без скобок if a > 0 \ and b > 0 \ and c < 10: pass Со скобками if (a > 0 # комент and b > 0 # комент and c < 10): pass Но прошу заметить, как порой страшно выглядят данные конструкции. Применяйте осторожно! Да и лишние скобки в Python смотрятся не всегда уместно) #tricks

680 views

Hashtags

Објавено 13 апр.

В предыдущем посте мы запускали нужную нам функцию внутри генератора списка. Выглядит странно, когда мы не сохраняем результат этого генератора, так как обычно нужен именно он. Обычно, в таких случаях более наглядно смотрится функция map(): array = [1, 2, 3, 4, 5, 6, 7, 8, 9] more, less = [], [] map(lambda x: [less.append, more.append][x>5](x), array) Проверяем результат >>> print(more, less) [] [] Хм, не сработало! Что произошло? Почему итерация не запустилась? Дело в том, что в Python3 многие итеративные функции (если не все) стали генераторами. А что такое генератор? Это не тот генератор списка который List Comprehensions, а именно Generator. Объект, который внутри себя имеет алгоритм получения следующего элемента и он не станет запускать итерацию пока мы не начнём запрашивать эти элементы. Что возвращает функция map()? >>> print(map(...)) <map object at 0x0000023114ADE3C8> Тоже самое произошло и с функцией range >>> print(range(10)) range(0, 10) Значит всё что остаётся, это запустить итерацию по элементам генератора. Как это сделать максимально коротко? Можно просто в цикле for for _ in map(...): pass Либо конвертнуть в список list(map(...)) Или оператором * [*map(...)] Ну а полностью будет выглядеть так [*map(lambda x: [less.append, more.append][x>5](x), array)] Теперь генератор сразу вычисляется. Хотя, как по мне, такая запись менее "читабельна") #tricks

787 views

Hashtags

Објавено 10 апр.

Как разделить один список на два по определённому признаку элементов? Самый очевидный способ выглядит так: array = [1, 2, 3, 4, 5, 6, 7, 8, 9] even, odd = [], [] for item in array: if item%2: odd.append(item) else: even.append(item) Смотрим что получается >>> odd [1, 3, 5, 7, 9] >>> even [2, 4, 6, 8] А теперь способ в одну строку! (ну кто бы сомневался😂) _ = [[even.append, odd.append][x%2](x) for x in array] Я специально сохранил результат в переменную "_", так как этот результат нам не нужен. Вся магия происходит во время выполнения генератора списка. Выражение x%2 возвращает нам 1 или 0, что является индексом списка [even.append, odd.append]. Таким образом происходит выбор метода append() для нужного списка и сразу после этого мы вызываем его, отправляя очередной элемент в выбранный список. Точно так же в выражение можно ставить сравнение, которое вернёт bool. Ведь вы помните, что bool это производный тип от int, а значит True это 1 а False это 0. >>> arr = [100, 200] >>> print(arr[True]) 200 >>> print(arr[False]) 100 В нашем случае можно сделать так more, less = [], [] [[less.append, more.append][x>5](x) for x in array] Можно даже никуда не сохранять результат, всё равно то что нам нужно произойдет. >>> print(more, less) [6, 7, 8, 9], [1, 2, 3, 4, 5] #tricks

859 views

Hashtags

Објавено 8 апр.

Небольшой трик с регулярными выражениями который редко вижу в чужом коде. Допустим, вам нужно распарсить простой текст и вытащить оттуда пары имя+телефон. Вернуть всё это надо в виде списка словарей. Возьмем очень простой пример текста. >>> text = ''' >>> Alex:8999123456 >>> Mike:+799987654 >>> Oleg:+344456789 >>> ''' Соответственно, для выделения нужных элементов будем использовать группы. Получится такой паттерн: (\w+):([\d+]+) Как мы будем формировать словарь из найденных групп? >>> import re >>> results = [] >>> for match in re.finditer(r"(\w+):([\d+]+)", text): >>> results.append({ >>> "name": match.group(1), >>> "phone": match.group(2) >>> }) >>> print(results) [{'name': 'Alex', 'phone': '8999123456'}, ...] Можно немного сократить запись используя zip >>> results = [] >>> for match in re.finditer(r"(\w+):([\d+]+)", text): >>> results.append(dict(zip(['name', 'phone'], match.groups()))) Но есть способ лучше! Это именованные группы в regex. Можно в паттерне указать имя группы и результат сразу забрать в виде словаря. >>> for match in re.finditer(r"(?P<name>\w+):(?P<phone>[\d+]+)", text): >>> results.append(match.groupdict()) То есть всё что я сделал, это добавил в начале группы (внутри сбокочек) такую запись: (?P<group-name>...) Теперь найденная группа имеет имя и можно обратиться к ней как к элементу списка >>> name = match['name'] Либо забрать сразу весь словарь методом groupdict() >>> match.groupdict() #tricks#regex

666 views

Објавено 4 апр.

Когда разрабатываете свой GUI с помощью PyQt для какого-либо софта бывает необходимо позаимствовать цвета из текущего стиля интерфейса. Например, чтобы правильно раскрасить свои виджеты, подогнав их по цвету. Ведь бывает, что ваш GUI используется в разных софтах. Причём некоторые со светлой темой а другие с тёмной. По умолчанию стили наследуются, но если вы задаёте какую-либо раскраску для части виджета через свой styleSheet, то требуется ссылаться на цвета текущего стиля. Как это сделать? Как получить нужный цвет из палитры имеющегося стиля? Это достаточно просто, нужно использовать класс QPalette и его роли. Например, мне нужно достать цвет текста из одного виджета и применить его в другом как цвет фона (не важно зачем именно так, просто захотелось😊). Получаем палитру виджета и сразу достаём нужный цвет, указав его роль. from PySide2.QtGui import QPalette color = main_window.palette().color(QPalette.Text) теперь можем использовать этот цвет в стилях my_widget.setStyleSheet(f'background-color: {color.name()};') Готово, мы динамически переопределили дефолтный стиль используя текущий стиль окна! На самом деле есть запись покороче, в одну строку и без лишних переменных. Не очень-то по правилам CSS, но Qt это понимает. my_widget.setStyleSheet('background-color: palette(Text);') Этот способ не подходит если вам нужно как-то модифицировать цвет перед применением в своих стилях. В этом случае потребуется первый способ. Зато он прекрасно сработает в файле .qss, то есть не придётся в коде прописывать раскраску отдельных элементов через ссылки на палитру, всё красиво сохранится в отдельном файле .qss! QListView#my_widget::item:selected { background: palette(Midlight); } Про имеющиеся роли можно почитать здесь🌍 #qt#tricks

598 views

Hashtags

Објавено 29 мар.

Что именно мы можем импортнуть из будущих версий? Явно не всё, иначе это была бы, собственно, новая версия. В ˍˍfutureˍˍ выносятся только ключевой функционал, от которого серьезно зависит синтаксис или использование возможностей языка. Самое очевидное это директива print, которая в Python3 стала функцией print(). from __future__ import print_function Что стало удобней с этой функцией? 🔸 Теперь это функция а не ключевое слово, её можно передать как аргумент или вернуть как результат def get_logger(): if condition: return some_handler.write else: return print 🔸 С помощью аргументов sep и end можем настроить минимальное форматирование вывода. sep: разделитель для нескольких объектов end: последний символ вместо перехода на новую строку >>> items1 = [1, 2, 3] >>> items2 = [4, 5, 6] >>> print(*items1, sep='-', end='-') >>> print(*items2, sep='-') 1-2-3-4-5-6 🔸 Аргумент flush форсированно пробрасывает буфер аутпута в файл. Полезно для вывода из блокирующих операций. Например, когда вам нужно в stdout выводить прогресс операции, запущенной в subprocess. Если не сделать flush то весь аутпут прилетит только по завершению процесса. for i in range(100): print(f'Progress: {i}%', flush=True) time.sleep(1) Этот прогресс мы можем отслеживать в реальном времени. А вот так приходилось делать раньше: import sys sys.stdout.write(text + '\n') sys.stdout.flush() 🔸 Аргумент file позволяет перенаправить вывод в другой поток. Например в файл, сеть или что угодно, что имеет метод write. print(text, file=open('filename.txt', 'w')) ___________ Ну да, теперь приходится писать лишние скобочки и сложно переучиться на новый лад. Но плюсов, я думаю, больше. #2to3#tricks

579 views

Hashtags

12•••101112131415
ПретходнаСтраница 12 од 15Следна