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Број на индексирани објави
Неодамнешен опфат6,906Збир на неодамнешни прегледи
Неодамнешни објави

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

Страница 25 од 32 · 384 објави

Објавено 22 јун.

Наверняка вы слышали о самом простом способе установить PIP, это скрипт get-pip.py. Скачиваем его, скармливаем интерпретатору и PIP установлен! python get-pip.py Но что это...??? Скрипт размером 1.8 МБ? Я думаю вы уже догадались почему. Смотрим докстринг в начале файла: ... This is a base85 encoding of a zip file, this zip file contains an entire copy of pip (version ХХ.Х.Х) ... Да, в скрипте сохранён ZIP архив! Он закодирован с помощью base85(аналог base64) записан в переменной DATA. Если вы сомневались что данный способ хранения данных бывает полезен, то вот вам яркий пример удобного инструмента на его основе. Один простой файл в котором есть всё что ему нужно 😎 #libs

556 views

Hashtags

Објавено 19 јун.

Ещё немного про base64. Собрал пример со встроенной в код картинкой. Это иконка для окна на PySide2. Файл кодирован в base64 и просто сохранён в переменной. Для использования этих данных даже не пришлось сохранять их в новый файл. Иконка создаётся на лету с помощью метода QPixmap.loadFromData() ... raw_data = base64.decodebytes(ico_encoded) ico = QPixmap() ico.loadFromData(raw_data, "PNG") ... 🌎 Полный пример смотрите в gists. #libs#tricks#qt

573 views

Објавено 17 јун.

Как сохранить картинку непосредственно в Python-модуль? Для этого нам пригодится библиотека base64. Этот способ кодирование позволяет любые бинарные или текстовые данные закодировать с помощью 64 ASCII символов. То есть получится простая строка. Зачем это вообще? Это обратимое кодирование позволит любые бинарные данные сохранить в текстовом виде и отправить туда где для записи поддерживается только текст. Например: - встроить в URL в GET запрос как параметр - встроить в тело email - сохранить в Python-модуль как переменную - сохранить любой конфиг, например JSON - записать в базу данных - зашить в HTML (XML) или CSS Чаще всего так кодируют изображения в HTML и в CSS. Есть даже специальные сервисы для кодирование изображений. Давайте закодируем и декодируем картинку. Кодирование: >>> import base64 >>> src_path = 'image1.png' >>> with open(src_path, 'rb') as f: >>> raw_data = f.read() >>> image_encoded = base64.encodebytes(raw_data) >>> print(image_encoded) b'iVBORw...Jggg==\n' Теперь наша картинка это просто байты в переменной. Её можно сохранить непосредственно в модуле и использовать позже. Декодирование: >>> save_path = "image2.png" >>> raw_data = base64.decodebytes(image_encoded) >>> with open(save_path, 'wb') as f: >>> f.write(raw_data) Картинка восстановлена обратно в файл. Стоит помнить что: - это не шифрование, пароли так не стоит прятать. Строка легко декодируется в исходник. - размер данных после кодирования увеличивается примерно на четверть - не храните изображения в базе данных таким способом! #libs#tricks

623 views

Hashtags

Објавено 15 јун.

В стандартной библиотеке os есть интересный метод os.nice(). Как написано в документации: Add increment to the process’s "niceness". Добавляет "любезности" процессу??? Ну почти... В Unix системах есть стандартная утилита nice, которая может контролировать приоритет использования CPU процессом. Обычно это значение 0, что значит стандартный приоритет. Но если добавить "любезности", то процесс будет больше отдавать другим, оставляя себе минимальный приоритет. Или наоборот. Запустим тест чтобы визуально увидеть разницу. 🔸 Загрузите процессор на 100%. Можно поставить любую тяжёлую задачу. Например, сохраните этот код в файл и запустите в консоли (Python3) 🔸Напишите функцию которая активно использует процессор и считает потраченное время. import time def compute(): array = [] for i in range(10): start = time.perf_counter() for i in range(1000000): x = 2*2 array.append(time.perf_counter()-start) return sum(array) / len(array) Моя функция запускает 10 раз некий код и возвращает среднее время. 🔸Тестируем import os # запускаем первый тест в дефолтным приоритетом t1 = compute() # меняем приоритет на минимальный os.nice(19) # запускаем второй тест t2 = compute() # смотрим реузльтат print("Test 1", t1, "sec") print("Test 2", t2, "sec") print("Diff", t2/t1, "times") В консоль распечатается время каждого теста и разница времени. 🌎 Код тестов 🔸 Где может пригодиться? - Повышение приоритета позволит захватывать больше процессорного времени, выполняя важные задачи быстрей. - Понижение приоритета позволит повысить отзывчивость компьютера во время выполнения тяжёлых расчётов. 🔸Что еще нужно помнить? - Чтобы добавить приоритет нужно в функцию os.nice() отправить отрицательное значение. Так как данный метод всегда прибавляет число к текущему приоритету. - Понижение приоритета доступно любому юзеру, повышение доступно только если процесс запущен от суперюзера. - Узнать текущее значение: os.nice(0) - Запускаемые подпроцессы наследуют приоритет. - работает только на Linux. - Доступный диапазон значений -20...19. #libs

693 views

Hashtags

Објавено 12 јун.

Расширенный вариант каунтера из прошлого примера. Оказалось ему есть куда еще развиваться и без унарных операторов))). Добавим обработку бинарных операторов "+" и "-". Сделаем возможность прибавлять к канутеру любое число обычным синтаксисом def __add__(self, other): self.val += int(other) def __sub__(self, other): self.val += int(other) Теперь можно делать так: >>> c = Counter(3) >>> c + 2 >>> print(c) Count: 5 Добавим обработку для случая когда наш каунтер справа def __radd__(self, other): self.__add__(other) def __rsub__(self, other): self.__sub__(other) >>> c = Counter(3) >>> 2 + с >>> print(c) Count: 5 Добавим во все методы возвращаемое значение и будем возвращать self: def __pos__(self, *args): self.val += 1 return self def __neg__(self): self.val -= 1 return self ... Тоже самое в остальных. Теперь такой синтаксис тоже допустим (и тоже антипаттерн!): >>> c = Counter() >>> print(c) Count: 0 >>> ++c Count: 2 >>> ++++c Count: 6 >>> ---c Count: 3 А так же теперь доступен такой вариант >>> c += 2 Count: 5 Следующие три записи идентичны по результату с += 2 с + 2 ++c Во всех случаях каунтер с увеличится на 2 Еще раз о главном! Все эти операции изменяют один из операндов, что не принято в Python. Так что дальше эксперементов не стоит уходить. Класс требует доработки чтобы не конфликтовать с принятыми нормами. 🌎Ссылка на полный листинг __________________________ PS. Если инкремент изменить на 0.5, то у нас получится синтаксис весьма похожий на C. То есть, чтобы прибавить 1 надо будет написать ++x 😎, но это совсем уже будет вне всяких приличий 🥴 #tricks

592 views

Hashtags

Објавено 10 јун.

В Python очень классной идеей является возможность переопределять взаимодействие объекта с любыми операторами, в том числе и унарные операторы. И это можно очень интересно применить! Долгое время меня смущало отсутствие возможности инкрементировать число на 1 с помощью синтаксиса С++. То есть вот так: val++ Эта команда просто прибавляет единицу к значению val. В Python аналогичная операция делается так: val += 1 Ну такой cебе ZEN😭. Давайте напишем класс, который сможет провернуть что-то подобное. А именно, сделаем чтобы величина значения увеличивалась на 1 с помощью такой записи: >>> c = Counter() >>> print(c) 0 >>> +c 1 Да, вместо x++ мы сделаем +x, чтобы не конфликтовать со стандартным синтаксисом. Но и это уже не плохо! Для взаимодействия с оператором "+" есть магический метод __add__, но для бинарного оператора. То есть когда операнда два. Для унарной версии оператора "+" есть метод __pos__, что означает positive. То есть как себя ведёт объект когда его пытаются сделать положительным. Вот его и используем: class Counter(object): def __init__(self, init=0): self.val = init def __pos__(self, *args): self.val += 1 def __repr__(self): return 'Count: {}'.format(self.val) Чтобы удобно было смотреть на результат, добавил метод __repr__. Проверяем что получится. >>> c = Counter() >>> print(c) Count: 0 >>> +c Count: 1 >>> +c Count: 2 Отлично, сделали счётчик с необычным синтаксисом! Добавим аналогичный метод для оператора "-" __neg__, что означает negate и описывает реакцию на попытку сделать число отрицательным. Теперь можем двигать значение в обе стороны: >>> class Counter(object): ... >>> def __neg__(self): >>> self.val -= 1 >>> c = Counter(5) >>> print(c) Count: 5 >>> +c Count: 6 >>> -c Count: 5 Стоит учесть, что данная реализация методов изменяет сам объект а не возвращает новый изменённый, как это принято в Python. Так что весь пример не очень Pythonic-way). Но такое решение реализует необходимый нам минималистичный синтаксис. Не буду утверждать, что пример получился полезным с точки зрения использования в реальной работе. Но для практики изучения вышло вполне интересно. #tricks

572 views

Hashtags

Објавено 8 јун.

Есть забавный трик с defaultdict, это бесконечно-рекурсивное дерево. Самое забавное что создать его можно в одну короткую строку. def tree(): return defaultdict(tree) Теперь можете создавать вложенные словари любой глубины! levels = tree() levels['lvl1']['lvl2']['lvl3'] = 'item' И таким образом строить любую иерархическую систему. Примеры и описание на странице автора: 🌎https://gist.github.com/hrldcpr/2012250 #tricks

589 views

Hashtags

Објавено 5 јун.

Бывают задачи когда из большого массива объектов требуется отфильтровать эти объекты по категориям. В результате получаем словарь примерно такого вида: data = { "category1": [item1, item2, ...], "category2": [item1, item2, ...], ... } При этом заранее мы не знаем список категорий и их необходимо добавлять в процессе итерации. Как такой код будет выглядеть: items = [...] sorted_items = {} for item in items: cat = get_category(item) if cat not in sorted_items: sorted_items[cat] = [] sorted_items[cat].append(item) Значением ключа является не сам элемент а промежуточный объект это список. Потому нам следует сначала убедиться, что он есть, а если нету то создать. Альтернативный код делающий тоже самое: for item in items: cat = get_category(item) if cat not in sorted_items: sorted_items[cat] = [item] else: sorted_items[cat].append(item) Чтобы избежать этой проверки можно использовать тип defaultdict, это очень простой класс который сам за вас сделает проверку и добавит нужный тип если его нет. Просто укажите нужный тип в конструкторе. from collections import defauldict items = [...] sorted_items = defaultdict(list) for item in items: sorted_items[get_category(item)].append(item) Если указанного ключа нет в словаре, то он создаётся сразу со списком в значении и возвращается как будто он там и был. #tricks#libs

553 views

Hashtags

Објавено 3 јун.

Порой бывает необходимо работать с JSON файлами ручками, читая или изменяя данные. И очень не удобно, когда юникод в файле записан в виде кодированных символов. >>> import json >>> data = {'title': 'Привет Медвед!'} >>> print(json.dumps(data)) '{"title": "\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442 \\u041c\\u0435\\u0434\\u0432\\u0435\\u0434!"}' Эх, безобразие! Ни прочитать нормально, ни поправить. Чтобы такое поведение изменить, достаточно добавить аргумент ensure_ascii=False >>> json.dumps(data, ensure_ascii=False) '{"title": "Привет Медвед!"}' Теперь символы не кодируются в Unicode. В файл запишется в таком же виде. ____________________ Для тех кто в танке (всё еще на Python 2🚂 ). Строку следует делать как unicode, и для записи в файл использовать модуль codecs. >>> import json, codecs >>> data = {'title': u'Привет Медвед!'} >>> with codecs.open(path, "w", encoding='utf-8') as f: >>> json.dump(data, f, ensure_ascii=False) #libs#tricks

543 views

Hashtags

Објавено 1 јун.

Часто используете Python в терминале? Скорее всего вас не особо устраивает дефолтный REPL. Советую попробовать прокаченные версии интерактивного шела: 🔸bpython - подсветка синтаксиса - автокомплиты - инлайн подсказки параметров функций - история команд - авто отступы Установка: pip3 install bpython Сайт 🌎 https://bpython-interpreter.org/ 🔸ptpython - подсветка синтаксиса - автокомплиты - поддержка мышки - авто отступы - цветовые темы Установка: pip3 install ptpython Сайт 🌎 https://github.com/prompt-toolkit/ptpython Также можно глянуть: ➡️www.asmeurer.com/mypython ➡️xon.sh ➡️ipython.org #libs

528 views

Hashtags

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

Схематичное представление структуры linked list

529 views

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

В стандартной поставке Python есть один полезный инструмент в библиотеке collections, это класс deque. он очень похож на простой список но он намного быстрее работает в некоторых случаях. Например для обработки элементов в начале списка у него есть дополнительные методы: extendleft(), appendleft() и popleft(). Запустим пару тестов!!! 🚀 >>> from collections import deque >>> import time >>> >>> st = time.perf_counter() >>> for _ in range(1000): >>> l1 = deque() >>> for i in range(5000): >>> l1.append(i) >>> en = round(time.perf_counter()-st, 3) >>> print(f'Test deque: {en}sec') >>> >>> st = time.perf_counter() >>> for _ in range(1000): >>> l2 = list() >>> for i in range(5000): >>> l2.append(i) >>> en = round(time.perf_counter()-st, 3) >>> print(f'Test list: {en}sec') Test deque: 0.452sec Test list: 0.436sec Добавление в конец списка работает примерно одинаково. Теперь попробуем вставлять элемент в начало массива. >>> st = time.perf_counter() >>> for _ in range(1000): >>> l1 = deque() >>> for i in range(5000): >>> l1.appendleft(i) >>> en = round(time.perf_counter()-st, 3) >>> print(f'Test deque: {en}sec') >>> >>> st = time.perf_counter() >>> for _ in range(1000): >>> l2 = list() >>> for i in range(5000): >>> l2.insert(0, i) >>> en = round(time.perf_counter()-st, 3) >>> print(f'Test list: {en}sec') Test deque: 0.435sec Test list: 6.347sec Прирост производительности почти в 15 раз! 😲 Тестим функцию pop() (опустим код теста для краткости) Test deque: 0.48sec Test list: 0.529sec Теперь pop(0) для list и popleft() для deque Test deque: 0.476sec Test list: 3.101sec Быстрей примерно в 6.5 раз. Почему так быстро? Дело в том что deque это некий аналог такого типа данных как "linked list data structure", в Python это занывается "двусвязные списки" (doubly-linked lists). Это список, но не в привычном представлении, а с особой оптимизированной структурой. При создании такого массива данные никуда не переносятся а только линкуются оттуда где были. Да, это похоже на Python-лист, но линковка происходит иначе. Вместо того чтобы собирать некий стек ссылок и назвать его списком, в doubly-linked list каждый элемент просто ссылается на следующий. Такая структура позволяет значительно ускорить, создание списка, изменение с любой стороны. Где это может пригодиться? Конечно же в двусторонних очередях (double-ended queue). То есть когда мы добавляем элементы в начало а забираем с конца, или наоборот. Минус такого подхода в просадке производительности для произвольного доступа к элементам в середине очереди. Полный код тестов 🌎 ______________ Реальное описание несколько сложней, я постарался передать основную суть. #libs#tricks

555 views

Hashtags

12•••10•••20•••2324252627•••303132
ПретходнаСтраница 25 од 32Следна