Вы когда-нибудь задавались вопросом, почему при создании приложения Python Flask вы передаете __name__
классу Flask?
Я определенно так считал, когда начал работать с Flask, и в этом уроке я хочу прояснить это для тех из вас, кто хотел бы узнать о нем больше.
Переменная __name__
передается в качестве первого аргумента при создании экземпляра объекта Flask (приложения Python Flask). В этом случае __name__
представляет имя пакета приложения и используется Flask для идентификации ресурсов, таких как шаблоны, статические ресурсы и папка экземпляра.
Лучший способ понять это — увидеть на практике.
Итак, давайте сделаем это!
Базовый пример того, как __name__
работает с Flask
Создайте новый каталог с именем flask-example, затем внутри этого каталога создайте виртуальную среду с именем venv и активируйте ее.
$ mkdir flask-example
$ cd flask-example
$ python3 -m venv venv
$. venv/bin/activate
(venv) $
Примечание: я создал отдельный учебник, который расскажет вам больше о виртуальных средах Python.
Затем обновите pip…
(venv) $ python3 -m pip install --upgrade pip
Collecting pip
Using cached pip-21.3.1-py3-none-any.whl (1.7 MB)
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 20.1.1
Uninstalling pip-20.1.1:
Successfully uninstalled pip-20.1.1
Successfully installed pip-21.3.1
…и установите Flask в вашей виртуальной среде с помощью pip:
(venv) $ pip install flask
Collecting flask
Using cached Flask-2.0.2-py3-none-any.whl (95 kB)
Collecting click>=7.1.2
Using cached click-8.0.3-py3-none-any.whl (97 kB)
Collecting Jinja2>=3.0
Using cached Jinja2-3.0.2-py3-none-any.whl (133 kB)
Collecting itsdangerous>=2.0
Using cached itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting Werkzeug>=2.0
Using cached Werkzeug-2.0.2-py3-none-any.whl (288 kB)
Collecting MarkupSafe>=2.0
Using cached MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl (13 kB)
Installing collected packages: click, MarkupSafe, Jinja2, itsdangerous, Werkzeug, flask
Successfully installed Jinja2-3.0.2 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 flask-2.0.2 itsdangerous-2.0.1
Теперь создайте файл app.py прямо внутри каталога flask-example. Этот файл будет иметь следующее содержимое:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def example():
return 'The value of __name__ is {}'.format(__name__)
В первой строке мы импортируем класс Flask из модуля Flask.
Затем вы создаете свое приложение и передаете переменную __name__
(произносится как «дандер метод») классу Flask.
Маршрут Flask возвращает значение __name__
, чтобы мы могли проверить его значение при запуске приложения Flask.
В операторе return мы использовали метод форматирования строки Python.
Чтобы запустить приложение, выполните следующую команду внутри каталога flask-example:
(venv) $ flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Если вы перейдете по адресу http://127.0.0.1:5000/ в своем браузере, вы увидите следующее сообщение:
The value of __name__ is app
Значение __name__
— app, имя текущего модуля Python.
Каково значение __name__
, когда приложение Flask находится внутри пакета?
Давайте посмотрим, как изменится значение __name__
, если мы переместим app.py внутрь пакета с именем example1.
Чтобы создать пакет example1, вам необходимо сделать две вещи:
- Создайте каталог с именем example1 в каталоге flask-example.
- Создайте файл с именем
__init__
.py внутри каталога example1.
(venv) $ mkdir example1
(venv) $ touch example1/__init__.py
Затем переместите app.py внутрь нового пакета:
(venv) $ mv app.py example1/
(venv) $ ls example1
__init__.py app.py
Запустите приложение Flask, выполнив команду «flask run» из каталога example1.
(venv) $ cd example1
(venv) $ flask run
Сообщение, которое вы видите в браузере при доступе к http://127.0.0.1:5000/, изменилось…
The value of __name__ is example1.app
Значение __name__
теперь равно example1.app.
Каково значение __name__
, если приложение Flask определено в __init__.py
пакета?
Давайте сделаем небольшое изменение по сравнению с предыдущим примером:
- Переместите код из app.py в
__init__.py
в пакете example1. - Удалите весь код из файла app.py.
Это можно сделать с помощью одной команды:
(venv) $ mv app.py __init__.py
Вот что происходит при попытке запустить приложение Flask:
(venv) $ pwd
/Coding/Python/Tutorials/flask-example/example1
(venv) $ flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Usage: flask run [OPTIONS]
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.
Согласно ошибке, Flask не может определить приложение для выполнения. Как вы можете видеть из ошибки, Flask ищет либо:
- Переменная среды
FLASK_APP
(которая не установлена). - Модуль в текущем каталоге с именем wsgi.py или app.py.
Давайте используем команду export, чтобы сообщить Flask, что приложение находится в текущем пакете, используя переменную среды FLASK_APP.
(venv) $ pwd
/Coding/Python/Tutorials/flask-example/example1
(venv) $ export FLASK_APP=.
(venv) $ flask run
* Serving Flask app "."
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Сообщение, возвращаемое нашим приложением:
The value of __name__ is example1
А что, если мы хотим запустить приложение из главного каталога нашего проекта? (родительский каталог example1).
(venv) $ cd..
(venv) $ pwd
/Coding/Python/Tutorials/flask-example
В этом случае нам необходимо установить значение FLASK_APP
на имя пакета: example1.
(venv) $ export FLASK_APP=example1
(venv) $ flask run
* Serving Flask app "example1"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Как и ожидалось, значение __name__ не изменится, учитывая, что наше приложение Flask все еще находится в пакете example1:
The value of __name__ is example1
Что означает __name__
при запуске приложения Flask?
Согласно этому руководству Flask, переменная __name__
используется для указания местонахождения приложения. Это необходимо для установки некоторых путей, используемых приложениями Flask.
Давайте посмотрим, что это за пути, углубившись в код Flask …
Прежде всего, вот как описывается первый параметр класса Flask:
:param import_name: the name of the application package
Это довольно очевидно…
Первый параметр, принимаемый конструктором класса Flask, — это имя пакета приложения. Вы можете передать его с помощью переменной __name__
(dunder name).
В строке документации класса Flask я вижу следующий раздел о первом параметре:
Таким образом, это подтверждает, что параметр import_name используется приложением Flask для поиска необходимых ему ресурсов (в файловой системе).
Интересно, что там говорится, что можно передавать значение __name__
как параметр import_name, если вы запускаете свое приложение в одном модуле. Например, так, как мы это сделали в первом примере этого руководства.
Но там также говорится, что…
Если мы запускаем наше приложение в модуле внутри пакета (например, yourapplication/app.py), хорошей практикой будет передать имя пакета в качестве первого параметра вместо __name__ из-за принципа работы некоторых расширений (например, Flask-SQLAlchemy)…
…если только вы не хотите извлечь имя пакета из __name__
, как показано в строке документации выше.
Зачем вы передаете __name__
классу Flask?
Мы увидели, что Flask использует значение переменной __name__
для идентификации ресурсов, используемых вашим приложением Flask.
Но для каких ресурсов Flask использует __name__
?
В предыдущем разделе мы увидели, что имя первого параметра, передаваемого при создании экземпляра класса Flask, называется import_name.
Вот пример использования этого параметра в коде Flask.
Метод auto_find_instance_path класса Flask
def auto_find_instance_path(self) -> str:
"""Tries to locate the instance path if it was not provided to the
constructor of the application class. It will basically calculate
the path to a folder named ``instance`` next to your main file or
the package.
.. versionadded:: 0.8
"""
prefix, package_path = find_package(self.import_name)
if prefix is None:
return os.path.join(package_path, "instance")
return os.path.join(prefix, "var", f"{self.name}-instance")
По сути, значение __name__, которое мы передаем в качестве первого аргумента, используется для определения местоположения папки экземпляра, если мы не передадим его конструктору класса приложения Flask (через параметр instance_path).
Папка экземпляра используется во Flask для хранения файлов конфигурации или ресурсов, которые изменяются во время выполнения. Она не должна находиться под контролем версий, и ее содержимое зависит от развертывания.
Давайте посмотрим, что возвращает этот метод, создав приложение Flask в оболочке Python.
Из каталога flask-example откройте оболочку Python и импортируйте пакет example1.
(venv) $ pwd
/Coding/Python/Tutorials/flask-example
(venv) $ python
Python 3.8.5 (default, Sep 4 2020, 02:22:02)
[Clang 10.0.0 ]:: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import example1
Используйте функцию dir()
, чтобы просмотреть свойства и методы, доступные в объекте example1.
>>> dir(example1)
['Flask', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'app', 'example']
Вы можете увидеть атрибут __name__
, значением которого, как мы уже видели, является имя пакета.
>>> example1.__name__
'example1'
Давайте вызовем метод auto_find_instance_path()
, используя объект app (экземпляр класса Flask).
>>> type(example1.app)
<class 'flask.app.Flask'>
>>> example1.app.auto_find_instance_path()
'/Coding/Python/Tutorials/flask-example/instance'
Это то место, где Flask создает папку экземпляра. Рядом с пакетом, где находится наше приложение Flask.
Каково значение __name__
при непосредственном запуске приложения Flask?
Для этого последнего упражнения переместите содержимое __init__.py
в файл app.py внутри пакета example1.
Не удаляйте файл __init__.py
.
На этом этапе __init__.py
будет пустым, а содержимое app.py будет следующим:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def example():
return 'The value of __name__ is {}'.format(__name__)
Теперь попробуйте запустить ваше приложение из каталога example1, вызвав app.py напрямую:
(venv) $ pwd
/Coding/Python/Tutorials/flask-example/example1
(venv) $ python app.py
(venv) $
Заметили, что ничего не происходит?
…это потому, что в нашем коде нет строки, которая запускает приложение.
Давайте добавим его в конец app.py:
app.run()
и затем снова запустите приложение:
(venv) $ python app.py
* Serving Flask app 'app' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Используйте браузер, чтобы проверить сообщение, возвращаемое маршрутом в приложении. Вы увидите следующее:
The value of __name__ is __main__
На этот раз значение __name__
равно __main__
(dunder main), поскольку мы вызвали наше приложение напрямую.
Заключение
Надеюсь, теперь стало понятнее, почему __name__
передается при создании приложения Flask.
Мы увидели, как значение __name__
меняется в зависимости от того, как мы структурируем наше приложение Flask: внутри модуля или пакета.
И теперь пришло время вам создать свое приложение с использованием Flask. Вы готовы?