Получи случайную криптовалюту за регистрацию!

Python Заметки

Логотип телеграм канала @pythonotes — Python Заметки P
Логотип телеграм канала @pythonotes — Python Заметки
Адрес канала: @pythonotes
Категории: Технологии
Язык: Русский
Количество подписчиков: 2.71K
Описание канала:

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

Рейтинги и Отзывы

3.00

3 отзыва

Оценить канал pythonotes и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

0

4 звезд

2

3 звезд

0

2 звезд

0

1 звезд

1


Последние сообщения 10

2021-03-03 12:01:06 Несмотря на то, что проекты линейки Qt For Python (все версии PySide и PyQt) считаются полноценными production-решениями, они всё еще недоделаны и постоянно развиваются. В частности, не все классы оригинального С++ фреймворка реализованы с Python-версиях.
Некоторые классы действительно пропущены за ненадобностью. Например, вместо QVariant можно использовать любой Python-объект, вместо QString простые Python-строки и тд.
Но есть классы до которых просто еще не добрались разработчики.

На этой странице можно посмотреть полный список нереализованных классов. При этом в разных биндингах состав может отличаться. К примеру те же QString и QVariant всё ещё доступны в PyQt4.

#qt
754 views09:01
Открыть/Комментировать
2021-03-01 12:00:38 Как получить класс из модуля зная только его dotted-path?
Что за dotted-path? Это путь импорта через точки вроде такого:

"package.module.clsName"

Так как мы не можем закинуть строку в директиву import то повторим то, что она делает только "вручную"

mod = __import__('package.module', fromlist=['clsName'])
cls = getattr(mod, 'clsName')

Похожий способ с importlib

import importlib
module = importlib.import_module('package.module')
cls = getattr(module, 'clsName')

В обоих случаях приходится дополнительно обрабатывать строку чтобы отрезать имя класса от имени модуля. Так как мы сначала импортим модуль а потом достаём из него нужный объект.

Есть ли способ просто закинуть всю строку и получить результат?

Если пишете проект на Django то в нём есть функция import_string(). Она используется для импорта объектов, указанных в settings.py в виде dotted-path.

from django.utils.module_loading import import_string
cls = import_string('package.module.clsName')

Если же у вас "чистый" Python то на помощь придёт модуль pydoc. У него тоже есть аналогичный метод для импорта объектов по dotted-path.

from pydoc import locate
cls = locate('package.module.clsName')
____________
Конечно же это не относится только к классам. Точно так же можно импортнуть любой объект, вложенный в модуль.

#tricks
655 viewsedited  09:00
Открыть/Комментировать
2021-02-24 12:00:23 20 Февраля 1991 года вышла первая beta-версия Python v0.9.0.
С тех пор минуло 30 лет!
Сегодня мы имеем один из самых популярных языков программирования в мире.

Поздравляем Python c юбилеем!

Узнать, как это было можно, поставив себе первый релиз с помощью conda

#offtop
455 viewsedited  09:00
Открыть/Комментировать
2021-02-19 12:00:23 Еще один пример с ресурсами.
Читаем картинку из PYZ архива сразу в QImage и далее используем как иконку в GUI.
Без сохранения в промежуточный файл!

Запускать так:
python3 pkg_img.pyz

Из зависимостей только PySide2.
Помним, что это просто ZIP. То есть исходники можно легко достать из архива.

#source
899 views09:00
Открыть/Комментировать
2021-02-17 12:01:14 Ранее я показал как упаковать ваше Python-приложение в ZIPAPP.
В дополнение к этой теме покажу ещё один способ как достать изображение из архива, не сохраняя его на диск и сразу перегнать в класс PIL.Image для дальнейших манипуляций.

Что есть ресурс в данном контексте? Это любой объект который можно прочитать как файл.

В Python 3.7 появился новый стандартный способ работы с ресурсами внутри пакетов. Это модуль importlib.resources.
Его следует использовать и для случаев с контейнерами (ZIP, EGG) и для обычных пакетов.

Для начала импортнём нужные модули

from importlib.resources import read_binary
from PIL import Image
import io

Читаем файл ресурса из пакета

data = read_binary("package_name", "image.jpg")

Создаём класс Image

img = Image.open(io.BytesIO(data))

Картинка загружена в память, можно с ней что-то делать

img.thumbnail((200, 200))

И после изменений сохранить в файл

img.save(path, 'JPG')

или использовать еще как-то

img.show()

Модуль получил бекпорт для старых версий в виде стороннего пакета importlib_resources.

До появления этого модуля использовался модуль pkg_resources, входящий в состав setuptools. Но он теперь неактуален.

#libs
1.2K views09:01
Открыть/Комментировать
2021-02-15 12:00:23 Как получить список всех модулей, доступных для импорта?

pip list

Эта команда выдаст список инсталлированных модулей, но не всех что доступны.

help('modules')
или
python -m pydoc modules

Покажет все модули которые можете импортнуть, включая те, что доступны благодаря переменной PYTHONPATH.
Уже лучше, но проблема лишь в том, что функция печатает всё в аутпут, а нам нужен список строк.

Конечно же в Python есть способ сделать всё просто и логично

import pkgutil
modules = [m.name for m in pkgutil.iter_modules()]

Вернёт имена всех модулей, доступных для импорта, кроме builtin модулей.
Просто добавим их отдельно:

import sys
modules.extend(sys.builtin_module_names)

Теперь мы получили полный список всех доступных для импорта модулей и пакетов, включая те, что подгружены через PYTHONPATH или динамически добавлены через sys.path.

#tricks
1.3K views09:00
Открыть/Комментировать
2021-02-12 12:00:00 Как правильно проверить атрибуты доступа файла? То есть доступна ли запись в файл или является ли он исполняемым?
Для этого в Python есть функция os.access()
Проверять так:

os.access(path, flag)

Функция вернёт bool в зависимости от наличия указанного флага.

Всего есть 4 флага проверки:

os.F_OK - наличие файла на диске
os.R_OK - доступ на чтение
os.W_OK - доступ на запись
os.X_OK - доступ на исполнение

Например, вместо try-except лучше делать так (пример из документации):

if os.access("myfile", os.R_OK):
with open("myfile") as fp:
return fp.read()

#basic #libs
1.5K views09:00
Открыть/Комментировать
2021-02-10 12:00:25
GUI для Pyinstaller

Auto PY to EXE — GUI-обёртка для Pyinstaller!
Создаём команду сборки с помощью диалога. Для профессионалов пользы не много, а начинающим будет интересно посмотреть какие есть основные опции у Pyinstaller и как они выглядят в команде.

Видео урок
Репозиторий
FAQ по использованию

PS. Пусть вас не смущает слово EXE в названии и Windows в уроке. Эта штука работает и на Linux и на MacOS.

#libs
1.6K views09:00
Открыть/Комментировать
2021-02-08 12:00:15 Как быстро отрезать от пути несколько элементов с любой стороны?
Например, есть длинный путь:

path = '/home/user/projects/proj1/assets/assetname/geo/publish/v001/body.geo'

Для удобного отображения логов (или еще какой-то абстрактной задачи) я хочу видеть только 3 последних элемента.

Сейчас мы не будем усложнять задачу с выделением только нужных элементов с парсингом самой строки. Работаем только с индексами элементов.
Учитываем, что путь может прийти с неизвестно куда направленными слешами.
Хочу реализацию в одну строку

Вот так можно это сделать с помощью модуля os.path

>>> os.path.join(
... *os.path.normpath(
... path
... ).replace(
... '\\', '/'
... ).split('/')[-3:])
'publish/v001/body.geo'

Монструозно, но работает

Более красивый вариант это класс pathlib.Path.
У него есть две функции, которые нам помогут

Свойство parts, которое возвращает список элементов пути.
Конструктор Path() может принимать несколько строк которые объединятся в один путь. То есть аналогично функции join.

>>> Path('folder', 'file')
PosixPath('folder/file')

Поэтому мы можем сделать так:

>>> Path(*Path(path).parts[-5:])
PosixPath('publish/v001/body.geo')

Ну вот, более лаконично (питонично )
А еще можно вырезать середину, оставив начало и конец

>>> p = Path(path)
>>> Path(*p.parts[:3],'...', *p.parts[-2:])
PosixPath('/home/user/.../v001/body.geo')

#tricks #libs
1.5K views09:00
Открыть/Комментировать
2021-02-05 12:00:16 Можно ли создать инстанс класса используя квадратные скобки вместо круглых?
Казалось бы, чего сложного, делаем метод __getitem__ как classmethod и готово

class MyClass:
def __init__(self, value):
self.value = value

@classmethod
def __getitem__(cls, item):
return cls(item)

Но нет, такой финт не сработает.

>>> inst = MyClass[5]
TypeError: 'type' object is not subscriptable

Тип данного класса не поддерживает такой интерфейс. Чтобы поддерживал, нужно изменять его метакласс.
Ниже представлен простой пример добавления метода __getitem__ в тип класса.

class PresetsType(type):
presets = {
'red': '#ff0000',
'green': '#00ff00',
'blue': '#0000ff'}

def __getitem__(self, item):
instance = self(self.presets[item])
return instance

Получилось что-то вроде пресетов, доступных при создании инстанса через квадратные скобки.
Теперь используем новый тип как метакласс нашего класса.

class Color(metaclass=PresetsType):
def __init__(self, value):
self.value = value

def __repr__(self):
return f''

Можно тестить!

# создаём инстанс обычным способом
>>> c1 = Color('#ffb905')
>>> print(c1)

# теперь через квадратные скобки
>>> c2 = Color['red']
>>> print(c2)


На сколько пример актуальный в реальной работе, решать вам. Но он точно неочевидный

Как еще можно это использовать?

как-либо модифицировать класс и возвращать тоже класс вместо готового инстанса
возвращать сразу список инстансов. Например, в случаях когда используется срез
возвращать разные версии классов по имени под разные ситуации, например унаследованные классы с доп. интерфейсом

UPD:
Начиная с версии 3.7 у появилась возможность сделать тоже самое без мета класса!
В PEP 560 добавили magic-метод __class_getitem__(cls).
Теперь наш класс будет выглядеть так:

class Color:
presets = {
'red': '#ff0000',
'green': '#00ff00',
'blue': '#0000ff'}

def __init__(self, value):
self.value = value

def __repr__(self):
return f''

def __class_getitem__(cls, item):
return cls(cls.presets[item])

Спасибо подписчикам за подсказку

#tricks
1.6K viewsedited  09:00
Открыть/Комментировать