Как работает функция reload()?
Эта функция нужна для того, чтобы перезагрузить изменившийся код из py-файла без рестарта интерпретатора.
Дело в том, что любой импортированный модуль при повторном импорте не будет перечитывать файл. Функция импорта вернёт уже загруженный в память объект модуля. Чтобы обновить код, нужно либо перезапустить всю программу, либо использовать функцию reload()
🔸 Перезагрузка пакета перезагрузит только его файл
🔸Она не может перезагрузить ранее не импортированный модуль.
🔸При вызове функция reload() перечитывает и перекомпилирует код в файле, создавая новые объекты. После создания новых объектов перезаписывается ранее созданный неймспейс этого модуля.
Это значит, что если где-то этот модуль импортирован через
Если какие-либо объекты из этого модуля импортированы через
Напишем простой модуль
Повторный импорт обновляет значение
#tricks #basic
Эта функция нужна для того, чтобы перезагрузить изменившийся код из py-файла без рестарта интерпретатора.
Дело в том, что любой импортированный модуль при повторном импорте не будет перечитывать файл. Функция импорта вернёт уже загруженный в память объект модуля. Чтобы обновить код, нужно либо перезапустить всю программу, либо использовать функцию reload()
from importlib import reload🔸 Функция reload() принимает в качестве аргумента только объект модуля или пакета. Она не может перезагрузить класс или функцию. Только весь файл целиком!
reload(my_module)
🔸 Перезагрузка пакета перезагрузит только его файл
__init__.py, если он есть. Но не вложенные модули. 🔸Она не может перезагрузить ранее не импортированный модуль.
🔸При вызове функция reload() перечитывает и перекомпилирует код в файле, создавая новые объекты. После создания новых объектов перезаписывается ранее созданный неймспейс этого модуля.
Это значит, что если где-то этот модуль импортирован через
import и обращение к атрибутам происходит через неймспейс (имя) модуля, то такие атрибуты обновятся. Если какие-либо объекты из этого модуля импортированы через
from то они будут ссылаться на старые объекты.Напишем простой модуль
# mymodule.py
x = 1
Теперь импортируем модуль и отдельно переменную х из модуля>>> import mymodule
>>> from mymodule import x
>>> print(mymodule.x)
1
>>> print(x)
1
Не перезапуская интерпретатор вносим изменения в модуль# mymodule.py
x = 2
Делаем перезагрузку модуля и проверяем х ещё раз>>> reload(mymodule)
>>> print(mymodule.x)
2
>>> print(x)
1
То же самое будет если присвоить любой объект переменной (даже словарь или список)Повторный импорт обновляет значение
>>> from mymodule import x
>>> print(x)
2
🔸Созданные инстансы классов не обновятся после перезагрузки модуля. Их придётся пересоздать.#tricks #basic
Telegram
Python Заметки
Подразумеваемые неймспейсы или неявные пакеты.
Этот функционал добавлен в Python 3.3
Что он означает?
Ранее, до 3.3 пакетами считались лишь директории, в которых есть файл __init__.py.
Этот файл одновременно являлся свидетельством того, что директория это…
Этот функционал добавлен в Python 3.3
Что он означает?
Ранее, до 3.3 пакетами считались лишь директории, в которых есть файл __init__.py.
Этот файл одновременно являлся свидетельством того, что директория это…
В PYTHONPATH или в sys.path можно указать путь к ZIP архиву с Python-модулями и пакетами.
Можно также указать вложенную директорию внутри архива.
WHL файлы тоже являются ZIP-архивами. Так что с ними это сработает тоже. Но у них иная задача и лучше так не делать.
#tricks
export PYTHONPATH=~/my_py_archive.zip
Всё будет выглядеть так, как если бы архив был директорией.Можно также указать вложенную директорию внутри архива.
export PYTHONPATH=~/my_py_archive.zip/lib
Следует только помнить, что в таком случае пути к модулям будут не актуальны. То есть переменная __file__ будет вести к файлу внутри архива, но с ним не стоит работать как с обычным файлом. >>> import main
>>> print(main.__file__)
'/home/user/my_py_archive.zip/main.py'
Если вы в архив поместили какие-то ресурсы, то следует сначала их извлечь во внешние файлы или загрузить в память прямо из архива.import pkgutil____________________
text = pkgutil.get_data(my_pkg.__name__, 'README.md')
WHL файлы тоже являются ZIP-архивами. Так что с ними это сработает тоже. Но у них иная задача и лучше так не делать.
#tricks
Вы уже знаете, что можно добавить ZIP архив в PYTHONPATH и использовать его как библиотеку.
У Python есть еще одна интересная стандартная библиотека zipapp. Она поможет создать стендалон (или почти стендалон) приложение с помощью ZIP архива.
На самом деле мы получим всё тот же архив но с некоторыми дополнениями
🔸 У него будет точка входа, то есть функция, которая запускается при старте приложения
🔸 У архива будет расширение PYZ, хотя, это тот же ZIP
🔸 Архив можно сделать исполняемым как простое приложение (только для Linux)
Давайте создадим простое приложение. Можно указать директорию или файл. Удобней всего делать приложение из директории. При этом все файлы внутри указанного пути попадут в архив.
Вот такая структура приложения у нас есть:
Вы скорее всего видели их в Bash-скриптах. Там написано с помощью какого интерпретатора запускать данный скрипт. В нашем случае надо дописать в начало ZIP-файла такую строку:
А вот так можно добавить эту строку ручками после создания архива
Что ещë можно сделать?
▫️Как видите, это не полноценный стендалон. Для запуска приложения всё ещë требуется Python в системе. Чтобы ваше приложение завелось на чистой системе можно добавить в директорию myapp все зависимости приложения, то есть любые нестандартные внешние библиотеки. Для работы приложения потребуется только сам Python.
▫️Можно добавлять любые файлы ресурсов. Для их использования потребуется извлечение этих файлов из архива. Например, если закинуть картинку в корень myapp
#tricks
У Python есть еще одна интересная стандартная библиотека zipapp. Она поможет создать стендалон (или почти стендалон) приложение с помощью ZIP архива.
На самом деле мы получим всё тот же архив но с некоторыми дополнениями
🔸 У него будет точка входа, то есть функция, которая запускается при старте приложения
🔸 У архива будет расширение PYZ, хотя, это тот же ZIP
🔸 Архив можно сделать исполняемым как простое приложение (только для Linux)
Давайте создадим простое приложение. Можно указать директорию или файл. Удобней всего делать приложение из директории. При этом все файлы внутри указанного пути попадут в архив.
Вот такая структура приложения у нас есть:
myapp/
app.py
А это код приложения# app.py
def main():
print('START APP')
Создаём ZIP-приложение:python3 -m zipapp myapp
Скорее всего вы получите ошибку, так как не указана точка входа.ZipAppError: Archive has no entry point
Чтобы это исправить следует в директории рядом с app.py создать файл __main__.py. Именно он будет выполняться при старте приложения. Либо просто указать флагом --main функцию внутри архива которую надо выполнить, и zipapp сам создаст этот файл с нужными импортами.python3 -m zipapp myapp --main=app:main
Мы получим файл myapp.pyz который можно запустить с помощью Python$ python3 ./myapp.pyz
START APP
Чтобы запускать это приложение просто по даблклику без дописывания python, следует сделать файл исполняемым и в начало дописать так называемый shebang line (только для Linux).Вы скорее всего видели их в Bash-скриптах. Там написано с помощью какого интерпретатора запускать данный скрипт. В нашем случае надо дописать в начало ZIP-файла такую строку:
#!/usr/bin/env python3
Это можно сделать с помощью флага --python
python3 -m zipapp myapp --main=app:main --python '/usr/bin/env python3'
Теперь в начало архива добавится нужная строка а сам файл станет исполняемым. А вот так можно добавить эту строку ручками после создания архива
echo '#!/usr/bin/env python3' > myapp2.pyz
cat ./myapp.pyz >> myapp2.pyz
chmod +x myapp2.pyz
Остаётся добавить флаг --compress чтобы сжать архив.python3 -m zipapp myapp --main=app:main --python '/usr/
bin/env python3' --compress
Можно сказать, что наше элементарное приложение готово😎Что ещë можно сделать?
▫️Как видите, это не полноценный стендалон. Для запуска приложения всё ещë требуется Python в системе. Чтобы ваше приложение завелось на чистой системе можно добавить в директорию myapp все зависимости приложения, то есть любые нестандартные внешние библиотеки. Для работы приложения потребуется только сам Python.
▫️Можно добавлять любые файлы ресурсов. Для их использования потребуется извлечение этих файлов из архива. Например, если закинуть картинку в корень myapp
myapp/
app.py
image.jpg
то достать её можно так:import pkgutil
# достаём данные
img_data = pkgutil.get_data('__main__', 'image.jpg')
# сохраняем в файл
open(filename, 'wb').write(img_data)
▫️На самом деле исполняемый файл можно сделать и для Windows, но там всё несколько сложней 😖#tricks
Telegram
Python Заметки
В PYTHONPATH или в sys.path можно указать путь к ZIP архиву с Python-модулями и пакетами.
export PYTHONPATH=~/my_py_archive.zip
Всё будет выглядеть так, как если бы архив был директорией.
Можно также указать вложенную директорию внутри архива.
export…
export PYTHONPATH=~/my_py_archive.zip
Всё будет выглядеть так, как если бы архив был директорией.
Можно также указать вложенную директорию внутри архива.
export…
Ранее мы уже говорили о том, как выполнить какой-либо код перед открытием интерактивной консоли.
Расскажу еще один способ! На самом деле, даже запустив интерпретатор в обычном режиме с выполнением скрипта из файла вы можете в любом месте активировать интерактивный режим. Или даже несколько по очереди. За это отвечает модуль code.
Как это может пригодиться?
🔸 Вам не хватает pdb и хочется больше "власти"
🔸 Нужно запросить у юзера данные в достаточно сложном виде. В этом случае можно попросить его создать что ему надо и сохранить в определённую переменную, с которой потом и работать.
🔸 Нужна изолированная среда для выполнения каких-либо действий.
🔸 Просто забавы ради😁
Запускается консоль очень просто
Я набросал простой пример с некоторым функционалом
🔹 Меняются символы приглашения
🔹 В неймспейсы добавляются дополнительные объекты
🔹 Считается время, проведённое в интерактивном режиме
🔹 Скрипт просит юзера заполнить переменную и по выходу распечатывает её значение
Код здесь ↗️
Для запуска сохраните код в файл и запускайте как обычный скрипт.
Расскажу еще один способ! На самом деле, даже запустив интерпретатор в обычном режиме с выполнением скрипта из файла вы можете в любом месте активировать интерактивный режим. Или даже несколько по очереди. За это отвечает модуль code.
Как это может пригодиться?
🔸 Вам не хватает pdb и хочется больше "власти"
🔸 Нужно запросить у юзера данные в достаточно сложном виде. В этом случае можно попросить его создать что ему надо и сохранить в определённую переменную, с которой потом и работать.
🔸 Нужна изолированная среда для выполнения каких-либо действий.
🔸 Просто забавы ради😁
Запускается консоль очень просто
import code
ic = code.InteractiveConsole()
try:
ic.interact()
except SystemExit:
pass
Выход обратно на предыдущий уровень происходит как обычно, вызов функции exit() или клавиши Ctrl+D (Ctrl+Z для Windows).Я набросал простой пример с некоторым функционалом
🔹 Меняются символы приглашения
🔹 В неймспейсы добавляются дополнительные объекты
🔹 Считается время, проведённое в интерактивном режиме
🔹 Скрипт просит юзера заполнить переменную и по выходу распечатывает её значение
Код здесь ↗️
Для запуска сохраните код в файл и запускайте как обычный скрипт.
python my_console.py
Для быстрого запуска можно сделать отдельный алиасalias py="python3 /home/username/my_console.py"
#tricks #sourceTelegram
Python Заметки
Startup скрипт для REPL.
Как выполнить скрипт сразу после старта интерактивной консоли Python?
Для начала понять бы зачем это может понадобиться. А причины бывают достаточно весомые
- автоматизировать одни и те же действия которые вы повторяете при старте…
Как выполнить скрипт сразу после старта интерактивной консоли Python?
Для начала понять бы зачем это может понадобиться. А причины бывают достаточно весомые
- автоматизировать одни и те же действия которые вы повторяете при старте…
Вы заметили что с интерактивной консолью из прошлого поста что-то не так? Что происходит если нажать стрелки вверх/вниз? Полный бардак!
Давайте поправим это дело!
Для сохранения и загрузки истории будем использовать специальный модуль readline.
Что добавлено?
🔸 Сохранение истории команд с возможностью выбора предыдущих (клавиши ⬆️⬇️ )
🔸 Сохранение истории в файл перед выходом из интерактива для будущих сессий
🔸 Автокомплит по нажатию клавиши TAB
🔸 Cписок вариантов автокомплита по двойному нажатию TAB
Код забираем здесь ↗️
#tricks #source
Давайте поправим это дело!
Для сохранения и загрузки истории будем использовать специальный модуль readline.
Что добавлено?
🔸 Сохранение истории команд с возможностью выбора предыдущих (клавиши ⬆️⬇️ )
🔸 Сохранение истории в файл перед выходом из интерактива для будущих сессий
🔸 Автокомплит по нажатию клавиши TAB
🔸 Cписок вариантов автокомплита по двойному нажатию TAB
Код забираем здесь ↗️
#tricks #source
Gist
my_console2.py
GitHub Gist: instantly share code, notes, and snippets.
Что делать если нужно поставить какую-то Python-библиотеку а root-прав нет? То есть в систему библиотеку никак и ничего не поставить.
Есть как минимум два способа это решить правильно!
🔸 Сделать виртуальное окружение и ставить там что угодно.
Это позволит создать полностью независимое исполняемое окружение для ваших приложений.
Все библиотеки будут храниться в домашней директории юзера а значит доступ на запись имеется.
Создать очень просто:
Это стандартный метод работы с любым проектом. Если еще не используете его, то пора начинать. Даже при наличии root доступа!
🔸 Бывает, что нет возможности запустить приложение из своего виртуального окружения. Например, его запускает какой-то сервис от вашего юзера и вставить активацию окружения вы не можете.
В этом случае можно установить библиотеки для Python не глобально в систему, а только для юзера.
Выполните этот код в консоли:
Именно сюда будут устанавливаться модули если добавить флаг
После неё можно запускать системный интерпретатор без виртуальных окружений и установленная библиотека будет доступна для текущего юзера.
Параметр
🔸 Дописывание пути в PYTHONPATH
Этот способ не входит в список "двух правильных", но тоже рабочий. Здесь придётся сделать всё несколько сложней.
Сначала ставим библиотеку в любое место указывая путь установки
Не буду советовать так делать. Единственный раз когда этот способ мне пригодился и решил поставленную задачу, это при создании общей библиотеки для кластера компьютеров.
Модули лежат в сети и подгружаются для всех из одного и того же места. То есть обновлять файлы требуется только один раз а не на всех хосты отдельно.
Минусы такого подхода:
▫️Нужно всем хостам пробить нужный путь в
▫️Чем больше хостов тем больше нагрузка на сеть. Иногда такой способ не подходит именно по этой причине. Тогда Ansible вам в помощь.
▫️Не очень подходит если хосты с разными операционками. Некоторые библиотеки различаются для Linux и Windows (там, где есть бинарники) и приходится мудрить более сложные схемы.
#tricks #basic
Есть как минимум два способа это решить правильно!
🔸 Сделать виртуальное окружение и ставить там что угодно.
Это позволит создать полностью независимое исполняемое окружение для ваших приложений.
Все библиотеки будут храниться в домашней директории юзера а значит доступ на запись имеется.
Создать очень просто:
python3 -m venv ~/venvs/myenvname
Теперь активируем окружение# Linux
source ~/venvs/myenvname/bin/activate
# Windows
%userprofile%\venvs\myenvname\Scripts\activate.bat
Можно ставить любые библиотеки и запускать приложение.Это стандартный метод работы с любым проектом. Если еще не используете его, то пора начинать. Даже при наличии root доступа!
🔸 Бывает, что нет возможности запустить приложение из своего виртуального окружения. Например, его запускает какой-то сервис от вашего юзера и вставить активацию окружения вы не можете.
В этом случае можно установить библиотеки для Python не глобально в систему, а только для юзера.
Выполните этот код в консоли:
python3 -m site
Вы получите что-то такое:sys.path = [
'/home/user',
'/usr/lib/python37.zip',
'/usr/lib/python3.7',
'/usr/lib/python3.7/lib-dynload',
'/home/user/.local/lib/python3.7/site-packages',
...
]
USER_BASE: '/home/user/.local'
USER_SITE: '/home/user/.local/lib/python3.7/site-packages'
ENABLE_USER_SITE: True
Нас интересует параметр USER_SITE. Это путь к пользовательским библиотекам, которые доступны по умолчанию, если они есть.Именно сюда будут устанавливаться модули если добавить флаг
--user при установке чего-либо через pippip install --user requests
Для этой команды не нужны root-права. После неё можно запускать системный интерпретатор без виртуальных окружений и установленная библиотека будет доступна для текущего юзера.
Параметр
USER_BASE показывает корневую директорию для хранения user-библиотек. Её можно изменить с помощью переменной окружения PYTHONUSERBASEexport PYTHONUSERBASE=~/pylibs
python3 -m site
...
USER_BASE: '/home/user/pylibs'
USER_SITE: '/home/user/pylibs/lib/python3.7/site-packages'
Получается некоторое подобие виртуального окружения для бедных 😁 которое можно менять через эту переменную (не делайте так! Лучше venv!)🔸 Дописывание пути в PYTHONPATH
Этот способ не входит в список "двух правильных", но тоже рабочий. Здесь придётся сделать всё несколько сложней.
Сначала ставим библиотеку в любое место указывая путь установки
pip3 install -t ~/mylibs modulename
Библиотека установится без привязки к какому-либо интерпретатору. То есть по умолчанию не будет видна. Теперь в нужный момент добавляем этот путь в sys.path или в PYTHONPATH. Не буду советовать так делать. Единственный раз когда этот способ мне пригодился и решил поставленную задачу, это при создании общей библиотеки для кластера компьютеров.
Модули лежат в сети и подгружаются для всех из одного и того же места. То есть обновлять файлы требуется только один раз а не на всех хосты отдельно.
Минусы такого подхода:
▫️Нужно всем хостам пробить нужный путь в
.bashrc или ещё куда-то чтобы он сетапился на старте.▫️Чем больше хостов тем больше нагрузка на сеть. Иногда такой способ не подходит именно по этой причине. Тогда Ansible вам в помощь.
▫️Не очень подходит если хосты с разными операционками. Некоторые библиотеки различаются для Linux и Windows (там, где есть бинарники) и приходится мудрить более сложные схемы.
#tricks #basic
Можно ли создать инстанс класса используя квадратные скобки вместо круглых? 🙄
Казалось бы, чего сложного, делаем метод
Ниже представлен простой пример добавления метода
Теперь используем новый тип как метакласс нашего класса.
Как еще можно это использовать?
🔸 как-либо модифицировать класс и возвращать тоже класс вместо готового инстанса
🔸 возвращать сразу список инстансов. Например, в случаях когда используется срез
🔸 возвращать разные версии классов по имени под разные ситуации, например унаследованные классы с доп. интерфейсом
Начиная с версии 3.7 у появилась возможность сделать тоже самое без мета класса!
В PEP 560 добавили magic-метод
Теперь наш класс будет выглядеть так:
Казалось бы, чего сложного, делаем метод
__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'<Color "{self.value}">'
Можно тестить!# создаём инстанс обычным способом
>>> c1 = Color('#ffb905')
>>> print(c1)
<Color "#ffb905">
# теперь через квадратные скобки
>>> c2 = Color['red']
>>> print(c2)
<Color "#ff0000">
На сколько пример актуальный в реальной работе, решать вам. Но он точно неочевидный😜Как еще можно это использовать?
🔸 как-либо модифицировать класс и возвращать тоже класс вместо готового инстанса
🔸 возвращать сразу список инстансов. Например, в случаях когда используется срез
🔸 возвращать разные версии классов по имени под разные ситуации, например унаследованные классы с доп. интерфейсом
Начиная с версии 3.7 у появилась возможность сделать тоже самое без мета класса!
В PEP 560 добавили magic-метод
__class_getitem__(cls).Теперь наш класс будет выглядеть так:
class Color:#tricks
presets = {
'red': '#ff0000',
'green': '#00ff00',
'blue': '#0000ff'}
def __init__(self, value):
self.value = value
def __repr__(self):
return f'<Color "{self.value}">'
def __class_getitem__(cls, item):
return cls(cls.presets[item])
Как быстро отрезать от пути несколько элементов с любой стороны?
Например, есть длинный путь:
▫️Сейчас мы не будем усложнять задачу с выделением только нужных элементов с парсингом самой строки. Работаем только с индексами элементов.
▫️Учитываем, что путь может прийти с неизвестно куда направленными слешами.
▫️Хочу реализацию в одну строку
Вот так можно это сделать с помощью модуля os.path
Более красивый вариант это класс pathlib.Path.
У него есть две функции, которые нам помогут
🔸 Свойство parts, которое возвращает список элементов пути.
🔸 Конструктор Path() может принимать несколько строк которые объединятся в один путь. То есть аналогично функции join.
А еще можно вырезать середину, оставив начало и конец
Например, есть длинный путь:
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 #libsGUI для Pyinstaller
Auto PY to EXE — GUI-обёртка для Pyinstaller!
Создаём команду сборки с помощью диалога. Для профессионалов пользы не много, а начинающим будет интересно посмотреть какие есть основные опции у Pyinstaller и как они выглядят в команде.
🎬 Видео урок
📦 Репозиторий
❓FAQ по использованию
PS. Пусть вас не смущает слово EXE в названии и Windows в уроке. Эта штука работает и на Linux и на MacOS.
#libs
Auto PY to EXE — GUI-обёртка для Pyinstaller!
Создаём команду сборки с помощью диалога. Для профессионалов пользы не много, а начинающим будет интересно посмотреть какие есть основные опции у Pyinstaller и как они выглядят в команде.
🎬 Видео урок
📦 Репозиторий
❓FAQ по использованию
PS. Пусть вас не смущает слово EXE в названии и Windows в уроке. Эта штука работает и на Linux и на MacOS.
#libs
Как правильно проверить атрибуты доступа файла? То есть доступна ли запись в файл или является ли он исполняемым?
Для этого в Python есть функция os.access()
Проверять так:
Всего есть 4 флага проверки:
Например, вместо try-except лучше делать так (пример из документации):
Для этого в 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Как получить список всех модулей, доступных для импорта?
Уже лучше, но проблема лишь в том, что функция печатает всё в аутпут, а нам нужен список строк.
Конечно же в Python есть способ сделать всё просто и логично😉
Просто добавим их отдельно:
#tricks
pip listЭта команда выдаст список инсталлированных модулей, но не всех что доступны.
help('modules')
илиpython -m pydoc modulesПокажет все модули которые можете импортнуть, включая те, что доступны благодаря переменной PYTHONPATH.
Уже лучше, но проблема лишь в том, что функция печатает всё в аутпут, а нам нужен список строк.
Конечно же в Python есть способ сделать всё просто и логично😉
import pkgutilВернёт имена всех модулей, доступных для импорта, кроме builtin модулей.
modules = [m.name for m in pkgutil.iter_modules()]
Просто добавим их отдельно:
import sysТеперь мы получили полный список всех доступных для импорта модулей и пакетов, включая те, что подгружены через PYTHONPATH или динамически добавлены через sys.path.
modules.extend(sys.builtin_module_names)
#tricks
Ранее я показал как упаковать ваше Python-приложение в ZIPAPP.
В дополнение к этой теме покажу ещё один способ как достать изображение из архива, не сохраняя его на диск и сразу перегнать в класс PIL.Image для дальнейших манипуляций.
Что есть ресурс в данном контексте? Это любой объект который можно прочитать как файл.
В Python 3.7 появился новый стандартный способ работы с ресурсами внутри пакетов. Это модуль importlib.resources.
Его следует использовать и для случаев с контейнерами (ZIP, EGG) и для обычных пакетов.
Для начала импортнём нужные модули
До появления этого модуля использовался модуль pkg_resources, входящий в состав setuptools. Но он теперь неактуален.
#libs
В дополнение к этой теме покажу ещё один способ как достать изображение из архива, не сохраняя его на диск и сразу перегнать в класс 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")
Создаём класс Imageimg = Image.open(io.BytesIO(data))Картинка загружена в память, можно с ней что-то делать
img.thumbnail((200, 200))И после изменений сохранить в файл
img.save(path, 'JPG')или использовать еще как-то
img.show()Модуль получил бекпорт для старых версий в виде стороннего пакета importlib_resources.
До появления этого модуля использовался модуль pkg_resources, входящий в состав setuptools. Но он теперь неактуален.
#libs
Telegram
Python Заметки
Вы уже знаете, что можно добавить ZIP архив в PYTHONPATH и использовать его как библиотеку.
У Python есть еще одна интересная стандартная библиотека zipapp. Она поможет создать стендалон (или почти стендалон) приложение с помощью ZIP архива.
На самом деле…
У Python есть еще одна интересная стандартная библиотека zipapp. Она поможет создать стендалон (или почти стендалон) приложение с помощью ZIP архива.
На самом деле…
pkg_img.pyz
8.7 KB
Еще один пример с ресурсами.
Читаем картинку из PYZ архива сразу в QImage и далее используем как иконку в GUI.
Без сохранения в промежуточный файл!
Запускать так:
▫️Помним, что это просто ZIP. То есть исходники можно легко достать из архива.
#source
Читаем картинку из PYZ архива сразу в QImage и далее используем как иконку в GUI.
Без сохранения в промежуточный файл!
Запускать так:
python3 pkg_img.pyz▫️Из зависимостей только PySide2.
▫️Помним, что это просто ZIP. То есть исходники можно легко достать из архива.
#source
20 Февраля 1991 года вышла первая beta-версия Python v0.9.0.
С тех пор минуло 30 лет! 😮
Сегодня мы имеем один из самых популярных языков программирования в мире.
Поздравляем Python c юбилеем! ⭐️🎉🎁🐍👍
Узнать, как это было можно, поставив себе первый релиз с помощью conda
#offtop
С тех пор минуло 30 лет! 😮
Сегодня мы имеем один из самых популярных языков программирования в мире.
Поздравляем Python c юбилеем! ⭐️🎉🎁🐍👍
Узнать, как это было можно, поставив себе первый релиз с помощью conda
#offtop
Python.org
Ancient Releases
The official home of the Python Programming Language
Как получить класс из модуля зная только его dotted-path?
Что за dotted-path? Это путь импорта через точки вроде такого:
Есть ли способ просто закинуть всю строку и получить результат?
Если пишете проект на Django то в нём есть функция import_string(). Она используется для импорта объектов, указанных в settings.py в виде dotted-path.
Конечно же это не относится только к классам. Точно так же можно импортнуть любой объект, вложенный в модуль.
#tricks
Что за dotted-path? Это путь импорта через точки вроде такого:
"package.module.clsName"Так как мы не можем закинуть строку в директиву import то повторим то, что она делает только "вручную"
mod = __import__('package.module', fromlist=['clsName'])
cls = getattr(mod, 'clsName')
Похожий способ с importlibimport 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Если же у вас "чистый" Python то на помощь придёт модуль pydoc. У него тоже есть аналогичный метод для импорта объектов по dotted-path.
cls = import_string('package.module.clsName')
from pydoc import locateВ Python3.9 добавили еще один способ ресолвинга имени в объект. Теперь это самый актуальный способ на данный момент!
cls = locate('package.module.clsName')
import pkgutil____________
cls = pkgutil.resolve_name('package.module.clsName')
Конечно же это не относится только к классам. Точно так же можно импортнуть любой объект, вложенный в модуль.
#tricks
Несмотря на то, что проекты линейки Qt For Python (все версии PySide и PyQt) считаются полноценными production-решениями, они всё еще недоделаны и постоянно развиваются. В частности, не все классы оригинального С++ фреймворка реализованы с Python-версиях.
Некоторые классы действительно пропущены за ненадобностью. Например, вместо QVariant можно использовать любой Python-объект, вместо QString простые Python-строки и тд.
Но есть классы до которых просто еще не добрались разработчики.
На этой странице↗️ можно посмотреть полный список нереализованных классов. При этом в разных биндингах состав может отличаться. К примеру те же QString и QVariant всё ещё доступны в PyQt4.
#qt
Некоторые классы действительно пропущены за ненадобностью. Например, вместо QVariant можно использовать любой Python-объект, вместо QString простые Python-строки и тд.
Но есть классы до которых просто еще не добрались разработчики.
На этой странице↗️ можно посмотреть полный список нереализованных классов. При этом в разных биндингах состав может отличаться. К примеру те же QString и QVariant всё ещё доступны в PyQt4.
#qt
В Python есть удобный почтовый debug-сервер. Он поможет проверить работу почты вашего web-проекта на этапе разработки без необходимости настраивать внешние сервисы или взаимодействие с реальными серверами Google или Yandex. Этот сервер просто печатает все сообщения в консоль.
Таким образом удобно дебажить одноразовые ссылки активации или просто факт отправки письма по расписанию.
Запускается очень просто:
Таким образом удобно дебажить одноразовые ссылки активации или просто факт отправки письма по расписанию.
Запускается очень просто:
python3 -m smtpd -n -c DebuggingServer localhost:1025Теперь настройте ваш проект на использование этого сервера. Например вот так настраивается Django:
# settings.py#django #tricks
if DEBUG:
EMAIL_HOST = 'localhost'
EMAIL_PORT = 1025
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False
DEFAULT_FROM_EMAIL = '[email protected]'
8 Марта🌸 вышел альфа-релиз Python 3.10.0a6
Уже сейчас можно его скачать и попробовать новый синтаксис Switch Statement, о котором я упоминал ранее.
В Python его назвали Structural pattern matching
Итак, как это теперь выглядит?
#tricks
Уже сейчас можно его скачать и попробовать новый синтаксис Switch Statement, о котором я упоминал ранее.
В Python его назвали Structural pattern matching
Итак, как это теперь выглядит?
match QUERY:Для объединения нескольких значений в одном кейсе используем вертикальную черту
case VALUE1:
return 1
case VALUE2:
return 2
case VALUE3:
return 3
case _: # default
return 0
match QUERY:Также можно добавлять дополнительные проверки с if
case VALUE1 | VALUE2:
return 3
case _: # default
return 0
match QUERY:Выглядит как синтаксический сахар для конструкции
case VALUE1:
return 1
case VALUE2 | VALUE3 if x < 5:
return 2
case _: # default
return 0
if..elif..else. В целом не плохо, но и непривычно)#tricks
Python.org
Python Release Python 3.10.0a6
The official home of the Python Programming Language
Для Python3.8 в PEP0578 добавили функционал аудита Runtime операций. Это позволяет выполнять хуки (функции) при возникновении определённых событий в интерпретаторе.
Этот функционал разработан, прежде всего, для специалистов по безопасности. Аудит позволяет перехватывать различные действия и проверять их допустимость.
Полный список стандартных аудит-ивентов можно посмотреть здесь. Из названий становится ясно что мы можем перехватить. Например, мы можем перехватить факт открытия файла (
Примеры использования:
▫️Представим, что после разработки и долгих тестирований веб сервиса вы могли где-то оставить функцию ручного ввода данных в консоль. На продакшене такое недопустимо. С помощью аудита можно вызвать исключение перехватив ивент
▫️Ивент
Как добавить свой хук?
Для первого теста выполните такой код в самом начале работы приложения
Теперь давайте посмотрим какие web-коннекты создаются при работе нашего кода. Для запросов используем requests.
А так же:
▫️есть платформозависимые хуки (например взаимодействие с winapi)
▫️можно писать хуки на Си
▫️так как это мера для обеспечения безопасности, нет способа удалить хуки после добавления.
Напоминаю, доступно в Python3.8+
#pep #tricks
Этот функционал разработан, прежде всего, для специалистов по безопасности. Аудит позволяет перехватывать различные действия и проверять их допустимость.
Полный список стандартных аудит-ивентов можно посмотреть здесь. Из названий становится ясно что мы можем перехватить. Например, мы можем перехватить факт открытия файла (
open), импорта модуля (import), копирование файла (shutil.copyfile), запуск процесса (subprocess.Popen) и тд. Как минимум мы можем залогировать данное событие, как максимум, вызвать аварийное завершение программы.Примеры использования:
▫️Представим, что после разработки и долгих тестирований веб сервиса вы могли где-то оставить функцию ручного ввода данных в консоль. На продакшене такое недопустимо. С помощью аудита можно вызвать исключение перехватив ивент
builtins.input
▫️С помощью ивента socket.getaddrinfo можно определить на какие сайты юзер заходил с помощью вашего приложения.▫️Ивент
exec позволит проверить загруженный объект кода перед его исполнением. Например выявить потенциально опасный код, или оставленные API ключи в строковых переменных.Как добавить свой хук?
Для первого теста выполните такой код в самом начале работы приложения
import sysКаждый хук вызывается для всех событий, поэтому мы можем с помощью одного хука увидеть всё что происходит в интерпретаторе.
def hook(event, args):
print(f'EVENT: {event}{args}')
sys.addaudithook(hook)
Теперь давайте посмотрим какие web-коннекты создаются при работе нашего кода. Для запросов используем requests.
import sysВ аутпуте вы увидите домен, на который был сделан запрос.
import requests
def socket_hook(event, args):
if event == 'socket.getaddrinfo':
print(args[0])
sys.addaudithook(socket_hook)
requests.get('https://google.com')
А так же:
▫️есть платформозависимые хуки (например взаимодействие с winapi)
▫️можно писать хуки на Си
▫️так как это мера для обеспечения безопасности, нет способа удалить хуки после добавления.
Напоминаю, доступно в Python3.8+
#pep #tricks
Python.org
PEP 578 -- Python Runtime Audit Hooks
The official home of the Python Programming Language