Python Заметки
2.31K subscribers
58 photos
2 videos
2 files
212 links
Интересные заметки и обучающие материалы по Python

Контакт: @paulwinex

⚠️ Рекламу на канале не делаю!⚠️

Хештеги для поиска:
#tricks
#libs
#pep
#basic
#regex
#qt
#django
#2to3
#source
#offtop
Download Telegram
Все мы любим pathlib за его краткость, логичность и ООП-подход.
История его появления в стандартных библиотеках это пример как надо интегрировать новые принципы в архитектуру языка программирования или любого приложения.
Расскажу кратко, по этапам:

🔸 Сначала у нас был os.path. Это функциональный подход который выглядит громоздко и многословно.

#пример переименования
import os

my_path = '/path/to/file.ext'
dir_name = os.path.dirname(my_path)
new_name = 'file2' + os.path.splitext(my_path)[1]
new_path = os.path.join(dir_name, new_name)
os.rename(my_path, new_path)

🔸 В версии 3.4 появилась библиотека pathlib которая поменяла ход игры. Теперь работаем с путями как с объектами. Кода стало меньше, счастья больше.

# пример переименования с pathlib
from pathlib import Path

my_path = Path('/path/to/file.ext')
new_path = my_path.with_name('file2').with_suffix(my_path.suffix)
my_path.rename(new_path)

🔸 С приходом этой сущности появились и проблемы, старые методы для работы с путями просто не понимают этот тип. Они работают только со строками.

my_path = Path('/path/to/file.ext')
open(my_path)
TypeError: invalid file: PosixPath('...')

То же самое с subprocess и остальными.

🔸Возникла задача адаптации всех стандартных методов для работы с данной библиотекой. Чтобы каждый из них смог понять объект Path и правильно его обработать. И самое интересное, как это было реализовано.

🔸 Если объект Path конвертнуть в строку str(Path) то мы получим правильный путь. Получается, что надо просто добавить форсированную конвертацию аргументов в str везде где это нужно? Нет!, так мы только всё усложим.

Просить юзеров конвертить в str когда нужно? Тоже нет, не pythonic-way.

В результате в Python 3.6 появляется новый абстрактный класс os.PathLike и понятие path-like object, который понимают все стандартные методы работы с файлами. Теперь, при написании библиотеки для работы с путями, ваша задача следовать правилам этого типа чтобы аккуратно вписаться в экосистему Python-путей.

А правила там простые, magic-метод ˍˍfspathˍˍ (file system path), который возвращает валидный путь.
Все методы для обработки файлов используют os.fspath() для объекта пути перед его использованием.

class MyPath(os.PathLike):
def __init__(self, val):
self.val = val

def __fspath__(self):
return self.val

path = MyPath('/path/to/file/ext')
f = open(path, 'w') # PROFIT!!!

Это сработает и без наследования от os.PathLike, Достаточно и только метода ˍˍfspathˍˍ. Но лучше всё же наследоваться, чтобы добавить дополнительные проверки субклассов.

А если наследоваться не получается то можно воспользоваться методом register

os.PathLike.register(MyPath)

Кстати, именно так и поступили в pathlib

🔸 Вывод

В этой истории показательно то, что вместо внесений изменений под конкретный случай (читай костыль), разработчики создали подходящие условия для всех.

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

Это принцип за который я сам всегда всеми руками ЗА.
Низкоуровневые решения не должны заниматься частными случаями. Если мы попробуем подстроиться под каждый необычный случай то получим жуткую кашу из if-else, try-except или еще чего похуже.

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

Если ваше решение начинается с if, это неверное решение!

#libs #tricks #pathlib