📂 Склеиваем пути правильно

Так делать плохо:

my_path = root + '/' + user + '/' + filename

Потому что:

• В разных ОС – разные разделители пути: ‘/’ для nix-подобных и macOS, ‘\\’ для Windows

• В компонентах могут быть или не быть слеши – легко допустить ошибку

• Набирать это даже не удобно (имхо)

Самый простой способ правильного склеивания путей – os.path.join выберет нужный разделитель и расставит его как надо:

my_path = os.path.join(root, user, filename)

Есть еще более современный и удобный способ, который также поставляется в стандартной библиотеке Python – модуль pathlib. Это библиотека для работы с путями и файлами в стиле ООП. Примечательно, что объект Path поддерживает оператор /, который собственно и склеивает пути:

my_path = Path(root) / user / filename

У класса Path есть куча методов для получения путей в разных форматах, извлечения компонент пути, получении инфо о файлах и папках и много другое. Вот лишь некоторые из них:

>>> Path('~').expanduser()
PosixPath('/Users/bob')
>>> Path('~/../../usr').expanduser().resolve()
PosixPath('/usr')

>>> Path.cwd()
PosixPath('/Users/bob')

>>> Path('/usr/bin/foo').parts
('/', 'usr', 'bin', 'foo')

>>> Path('my/library.tar.gar').suffixes
['.tar', '.gar']

>>> Path('my/library.tar.gar').parent
PosixPath('my')

>>> str(Path('/usr/bin/foo'))
'/usr/bin/foo'

>>> sorted(Path('Projects/playground_python').glob('*.py'))
[PosixPath('Projects/playground_python/btc_gen.py'), PosixPath('Projects/playground_python/getattr.py'), ...]

>>> Path('test.txt').touch()
>>> Path('test.txt').exists()
True
>>> Path('test.txt').is_file()
True
>>> Path('test.txt').is_dir()
False
>>> Path('test.txt').is_symlink()
False

>>> Path('temp/1/foo').mkdir(parents=True, exist_ok=True)
>>> Path('temp/1/foo').resolve().as_uri()
'file:///Users/bob/temp/1/foo'
>>> Path('temp/1/foo').rmdir()

И еще очень много всего!

🤩 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway! 👈

🤭 Счастливой отладки

Python не запрещает создавать переменные и функции с именами, идентичными встроенным. Шутки ради переопределим print:

import sys

# счастилвой отладки!
def print(*values, sep=' ', end='\n', file=sys.stdout, flush=False):
    # шутка
    def joke(value):
        if type(value) is str:
            value = value[::-1]
        elif type(value) is int:
            value += 1
        return value

    # отсюда достанем исходную версию print
    import builtins
    return builtins.print(*map(joke, reversed(values)),
                          sep=sep, end=end, file=file, flush=flush)


print('Hello, world!', '2 x 2 =', 4)  # 5 = 2 x 2 !dlrow ,olleH

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

🤩 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway!👈

​​🔄 Визуализация графа ссылок

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

0) Для рисования графов понадобится graphviz Например, на MacOS вы можете установить его через Homebrew:

brew install graphviz

1) Установим библиотеку objgraph:

pip install objgraph

2) Использование. Пусть у нас есть такая структура данных:

x = ["test"]
x.append(x)
y = [x, [x], dict(x=x), set([1, 2, "test"])]

Сохраняем граф ссылок на объекты, на которые ссылается y в файл ‘1.png’. Обратите внимание, что show_refs принимает именно список [y], а не просто y:

import objgraph
objgraph.show_refs([y], filename='1.png')

Можно для каждого объекта вывести общее число ссылок на него:

objgraph.show_refs([y], refcounts=True, filename='2.png')
Пример вывода objgraph

А можно узнать, кто наоборот ссылается на интересующий объект x, т.е. отследить цепочку ссылок до глобальных объектов:

objgraph.show_backrefs([x], filename='3-back.png')

Узнать статистику по самым распространенным объектам в текущей среде:

>>> objgraph.show_most_common_types(limit=5)
function           2127
dict               1193
wrapper_descriptor 1002
tuple              954
weakref            868

Или по конкретному типу глобально:

>>> objgraph.count('dict')
1195

Или среди конкретного списка объектов:

>>> objgraph.count('dict', [{'x':5}, {'y':6}])
2

В библиотеке еще много функций для отслеживания ссылок и статистик по объектам, но всего этого не вместить в небольшую заметку.

👉 Общая документация по objgraph 

👉 Список функций objgraph

👨‍🎓Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway! 👈