Модуль – это единственный файл с функциями и классами.
Пакет – это два и более модулей. В python файловая структура пакета выглядит так:
package/
__init__.py
foo.py
bar.py
Библиотека – набор пакетов.
Фреймворк – набор библиотек.
# Установить пакет
pip install <package>
# Установить пакет для текущего пользователя
# Для работы скриптов требует строки в .zshrc «export PATH=$HOME/.local/bin:$PATH»
pip install --user <package>
# Удалить пакет
pip uninstall <package>
# Удалить все пакеты
pip freeze | xargs pip uninstall -y
# Обновить пакет
pip install -U <package>
# Сохранить пользовательские пакеты вместе с их версиями в файл
pip freeze > requirements.txt
# Установить список пакетов из файла
pip install -r requirements.txt
Это скрипт на баше, который позволяет управлять версиями Python.
Проблема: в дистрибутивах Linux часто по-умолчанию установлена довольно старая версия интерпретатора. Ее замена может повляить на работоспособность системы. Если нужна специфическая версия Python, то ее можно поискать в репозиториях, либо собрать самому. Вместо команды python придется использовать python3.6, вместо pip – pip3 и т.д.
Перед началом установки следует установить все необходимые зависимости, следуя этой инструкции.
# Лучше всего ставить pyenv по-старинке, так как при установке через пакетные менеджеры не работает обновление
curl https://pyenv.run | bash
# Добавляем в конец файла эти строки
$ nano .bashrc
...
export PATH=$HOME/.pyenv/bin:$PATH
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
# Для zsh редактируем переменную
$ nano .zshrc
plugins=(
...
pyenv
...
)
# Без этого не будет работать автоподстановка для команд
autoload -Uz compinit && compinit
# Ставим плагин для обновления
$ git clone git://github.com/pyenv/pyenv-update.git $(pyenv root)/plugins/pyenv-update
# Периодически обновляем pyenv (через какое-то время после установки). Можно отредактировать .zshrc и включить автоматическое обновление
$ pyenv update
# Смотрим доступные версии Python для установки
$ pyenv install --list
# Устанавливаем определенную версию Python
$ pyenv install 3.7.3
# Делаем ее глобальной
$ pyenv global 3.7.3
# Или локальной: команда python будет вызывать python 3.7.3 в текущем каталоге и ВО ВСЕХ ДОЧЕРНИХ!!!
$ pyenv local 3.7.3
# Проверяем
$ python
Python 3.7.3 (default, Mar 26 2019, 21:43:19)
[GCC 8.2.1 20181127] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
Проблема: при разработке может возникнуть конфликт версий библиотек, так как pip позволяет установить только одну версию библиотеки.
# Создаем виртульное окружение
$ python -m venv .venv
# Активируем его
$ . .venv/bin/activate
# Устанавливаем модули
(.venv) $ pip install -r requirements.txt
# Дактивируем виртуальное окружение
(.venv) $ deactivate
Как выглядит типичный процесс разработки:
# Устанавливаем кучу модулей
$ pip install ...
# Пишем кучу кода
# Сохраняем зависимости
$ pip freeze > requirements.txt
# Публикуем проект
$ git add .
$ git commit -m "some changes"
$ git push
# На сервере
$ git pull
$ pip install -r requirements.txt
При таком подходе возникает проблема: управление зависимостями для продакшена и разработки. Во время разработки используются, например, pylint и pytest. Эти модули не нужны в продакшене. pip freeze
по-мимо самих библиотек сохраняет кучу зависимостей, что не позволяет убирать лишнее из requirements.txt вручную.
Решения:
- Использовать pip-tools. pip-compile генерирует requirements.txt из requirements.in и setup.py. Т.е. в нем предлагается вручную прописывать зависимости.
- pipenv – очередное из серии %something% for Humans. Проблему в принципе решает. Аналог npm. Умеет создавать виртуальные окружения. Небольшой туториал pyenv+pipenv.
- poetry. То же самое, что и pipenv только функционал по-богаче.
# Устанавливаем модуль
$ pip install poetry
# Если не используется Pyenv, то Poetry лучше установить в домашний каталог
$ pip install -U poetry
# Добавляеми автоподстановку для Oh-My-Zsh
$ mkdir $ZSH/plugins/poetry
$ poetry completions zsh > $ZSH/plugins/poetry/_poetry
$ nano ~/.zshrc
# Добавляем плагин
$ nano .zshrc
plugins=(
...
poetry
...
)
# Виртуальное окружение будет создаваться в каталоге проекта
$ poetry config settings.virtualenvs.path .venv
# Путь по-умолчанию: ~/.cache/pypoetry/virtualenvs/<projectname>-py<vresion>
# Создаем новый проект
$ poetry new <project-name>
# Для создания проекта в интерактивном режиме
$ poetry init
$ cd <project-name>
# Перед добавление библиотек через poetry нужно активировать виртуальное окружение
# иначе он добавит модуль в зависимости и установит его глобально. Это баг?
# Может какие-то системные переменные окружения не установлены?
$ source $(poetry env info -p)/bin/activate
# Добавляем зависимости
$ poetry add requests
# Добавляем библиотеку с github
$ poetry add Flask-Restless --git https://github.com/jfinkels/flask-restless.git
# Добавляем зависимости для разработки
$ poetry add pylint --dev
# Удаление
$ poetry remove <library>
# Обновление
$ poetry update <library>
# Запуск приложения
$ poetry run python app.py
# Запуск тестов
$ poetry run python -m unittest discover
# Собрать пакет
$ poetry build
# Загрузить собранный пакет в pypi
$ poetry publish
# Poetry не читает ~/.pypirc, поэтому нужно отредактировать два файла с настройками
$ nano ~/.config/pypoetry/config.toml
[repositories]
pypi = {url = "https://upload.pypi.org/legacy/"}
testpypi = {url = "https://test.pypi.org/legacy/"}
$ nano ~/.config/pypoetry/auth.toml
[http-basic]
pypi = {username = "myuser", password = "topsecret"}
testpypi = {username = "myuser", password = "topsecret"}
# Если этих файлов не существует, то нужно выполнить, эта команда создаст настройки
$ poetry config
# Покажет все настройки
$ poetry config --list
# Путь до виртуального окружения
$ poetry run which python
# Показать зависимости
$ poetry show
# Активировать virtualenv
$ poetry shell
# Запустить тесты
$ poetry run pytest tests
# Создание скриптов
$ nano pyproject.toml
[tool.poetry.scripts]
# <package>:<function>
hello = 'scripts:hello'
$ nano scripts/__init__.py
def hello(*args, **kw):
print('Hello, World!')
# Запуск скрипта
$ poetry run hello
# Установить пакет в виртуальное окружение
$ poetry install
# То же самое, но без зависимостей для разработчика
$ poetry install --no-dev
# Обновить poetry
$ poetry update:self
Чтобы загружать пакеты в PyPi нужно:
# Добавить pypi в репозитории
$ vim ~/.config/pypoetry/config.toml
...
[repositories]
pypi = {url = "https://upload.pypi.org/legacy/"}
# Прописать свои креды
$ vim ~/.config/pypoetry/auth.toml
[http-basic]
pypi = {username = "tz4678", password = "***"}
Ссылки:
Обновим pip:
pip install --upgrade pip
Установим Poetry:
pip install -U poetry
Создадим новый проект:
poetry new hello-world
Перейдем в каталог проекта:
cd hello-world
Отредактируем hello_world/__init__.py
:
__version__ = '0.1.0'
def hello(*args, **kw):
print('Hello, World!')
Изменим файл pyproject.toml
, добавив пару строк:
[tool.poetry.scripts]
# <package>:<function>
hello = "hello_world:hello"
Проверим работу скрипта:
$ poetry run hello
Hello, World!
Это обычный консольный скрипт:
sergey@sergey-pc ~/Development/hello-world . ~/.cache/pypoetry/virtualenvs/hello-world-py3.7/bin/activate
(hello-world-py3.7) sergey@sergey-pc ~/Development/hello-world hello
Hello, World!
Перед публикацией проекта нужно зарегистрироваться на pypi , а после регистрации создать файл ~/.pypirc
с кредами:
[pypi]
username: <username>
password: <password>
Публикация проекта проста:
poetry publish
Для начала нужно зарегистрироваться на портале. Это можно сделать через веб-сайт либо консоль.
После регистрации создаем файл ~/.pypirc
:
[distutils]
index-servers =
pypi
[pypi]
repository: https://pypi.python.org/pypi
username: <username>
password: <password>
Расписывать процесс создания setup.py
нет смысла, в виду того что с современными пакетными менеджерами типа Poetry, которые все это автоматизируют, в этом нет смысла. Для общего развития можно почитать инструкцию с официального сайта.
import logging
import logging
# This sets the root logger to write to stdout (your console)
logging.basicConfig()
# By default the root logger is set to WARNING and all loggers you define
# inherit that value. Here we set the root logger to NOTSET. This logging
# level is automatically inherited by all existing and new sub-loggers
# that do not set a less verbose level.
logging.root.setLevel(logging.NOTSET)
# The following line sets the root logger level as well:
logging.basicConfig(level=logging.NOTSET)
# You can either share the `logger` object between all your files or the
# handle `my-app`. The result is the same.
logger = logging.getLogger("my-app")
logger.info("this will get printed")
# In large applications where you would like more control over the logging,
# create sub-loggers from your main application logger.
component_logger = logger.getChild("component-a")
component_logger.info("this will get printed with the prefix `my-app.component-a`")
# If you wish to control the logging levels, you can set the level anywhere in the
# hierarchy:
#
# - root
# - my-app
# - component-a
#
# Example for development:
logger.setLevel(logging.DEBUG)
# If that prints too much, enable debug printing only for your component:
component_logger.setLevel(logging.DEBUG)
# Create a file handler
handler = logging.FileHandler('hello.log')
handler.setLevel(logging.INFO)
# Create a logging format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # Gets applied to all the loggers
handler.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(handler)
# Types : debug, info, warning, error and critical
logger.info('Basic Info, Routine Calls')
logger.debug('More detailed data values for debugging')
logger.warn('Important informations')
logger.error('Error Signal') #, exc_info=True) #for giving execution trace
logger.critical('critical message')
VSCode – это лучший текстовый редактор для программирования на Python. Он бесплатен и вместе с расширениями превращается в полноценную IDE.
Почитать это. А тут есть пример с gunicorn.
Доступно после установки расширения IntelliCode.
$ poetry add autopep8 --dev
Пример настроек:
{
...
"python.formatting.autopep8Args": [
"--indent-size=2",
"--max-line-length=120",
"--experimental"
],
"python.formatting.provider": "autopep8",
...
}
Настройки можно как для проекта задать, так и глобально. Форматирование будет работать по сочетанию Ctrl + Shift + I
. Подробнее.
is
проверяет ссылаются ли аргументы на один объект, а ==
— на одинаковое значение, поэтому
class Foo:
def foo(self):
print('foo')
class Bar:
def foo(self):
print('bar')
class Baz(Foo, Bar):
...
Baz().foo() # prints foo
# Правильно в обратном порядке
class Baz(Bar, Foo):
...
Baz().foo() # prints bar
def foo(f):
def wrap(*args, **kw):
print('foo')
return f(*args, **kw)
return wrap
def bar(f):
def wrap(*args, **kw):
print('bar')
return f(*args, **kw)
return wrap
@foo
@bar
def baz():
...
baz()
Вывод:
foo
bar
The explanation that
yield from g
is equivalent tofor v in g: yield v
# Декартово произведение множеств: находим все возможные компибаниции
>>> [a + b for a in 'ABC' for b in 'xy']
['Ax', 'Ay', 'Bx', 'By', 'Cx', 'Cy']
Создаем консольную утилиту на Python с помощью Poetry
Обновим pip:
Установим Poetry:
Создадим новый проект:
Перейдем в каталог проекта:
cd hello-world
Отредактируем
hello_world/__init__.py
:Изменим файл
pyproject.toml
, добавив пару строк:<package>:<function>
.Проверим работу скрипта:
$ poetry run hello Hello, World!
Это обычный консольный скрипт:
Перед публикацией проекта нужно зарегистрироваться на pypi , а после регистрации создать файл
~/.pypirc
с кредами:Публикация проекта проста: