Azure Functions Python Programming Model v1 と v2 の違い

2023/09/04に公開

Azure Functions の最新の 4.x version では、C#、JavaScript、Java、Powershell、Python、TypeScript など様々な言語が使用可能です。
中でも、Python を使用する際には、Python v1 プログラミングモデルと、Python v2 プログラミングモデルがあります。
なお、ここでいう v1 や v2 は Python 自体のバージョンとは関係ありません。あくまで、Functions で Python を使用する際のプログラミングモデルの話です。
v2 のプログラミングモデルでは、Functions アプリケーションを簡単に作成できるようになり、Functions 特有の概念が少なくなり、代わりに Python の原則が強調されています。
主な改良点としては、Python のデコレートを使用して Functions で必要なトリガーとバインディングが宣言されるようになったり、フォルダ構造がシンプルになったり、ドキュメントが参照しやすくなったなどが挙げられます。
なお、v2 モデルを活用することで、関数の作成方法は変わりますが、モニタリング、デバッグ、デプロイに関する基本的な方法は変わりません。

The v2 programming model enables customers to easily create Functions applications – leaning towards fewer Functions concepts and instead emphasizing Python principles. Key improvements include triggers and bindings declared as decorators, a simplified folder structure, and easy to reference documentation.
Note that leveraging the v2 model will alter how you create functions, but the underlying experience regarding monitoring, debugging, and deployment will remain the same.

Python v1 と Python v2 プログラミングモデル

ここからは Python v1 プログラミングモデルと Python v2 プログラミングモデル の違いを書いていきます。

Python v1 Python v2
1.関数作成方法 ・Visual Studio Code
・ターミナル/コマンドプロンプト
・Azure Portal
・Visual Studio Code
・ターミナルまたはコマンドプロンプト
2.関数エントリポイント _init_.py (代替エントリポイントも指定可能) function_app.py
3.トリガーとバインドの宣言 function.json で宣言 関数と同じファイル (function_app.py) で宣言
4.フォルダー構造 (詳細後述) (詳細後述)

1. 関数作成方法

Python v1 プログラミングモデル は Portal 経由でも作成できるが、Python v2 プログラミングモデル は Portal 経由では作成できないという差異があると思います。

2. 関数エントリポイント

v1
既定では、ランタイムは main() というグローバルメソッドが _init_.py ファイル内に実装されると想定されている。
また、function.json ファイル内で、scriptFile プロパティと entryPoint プロパティをオプションで指定することで、既定のエントリポイントから任意のエントリポイントに変更できます。
例えば、以下の function.json では、エントリポイントとして main.py ファイル内の customentry() メソッドを使用するようにランタイムに指示しています。

function.json
{
  "scriptFile": "main.py",
  "entryPoint": "customentry",
  "bindings": [
      ...
  ]
}

v2
既定では、ランタイムは グローバルメソッドが function_app.py ファイル内に実装されると想定されている。
エントリポイントは function_app.py ファイル内にあります。

3. トリガーとバインドの宣言

v1
トリガーとバインディングからのデータをメソッド属性を介して関数にバインドするためには、function.json ファイル内で定義されている name プロパティを使用します。
下記のコードは visual studio code より、http トリガー関数を作成した際の例となります。

function.json
{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}
__init__.py
import logging
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

v2
トリガーとバインディングを宣言するためには Python のデコレータを使用します。
これらは、関数と同じファイル function_app.py で定義されます。
下記のコードは visual studio code より、http トリガー関数を作成した際の例となります。

function_app.py
import azure.functions as func
import logging

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

@app.route(route="HttpTrigger1")
def HttpTrigger1(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

4. フォルダ構造

v1
公開ドキュメントに記載されている推奨フォルダ構造

<project_root>/
 | - .venv/
 | - .vscode/
 | - my_first_function/
 | | - \__init__.py
 | | - function.json
 | | - example.py
 | - my_second_function/
 | | - \__init__.py
 | | - function.json
 | - shared_code/
 | | - \__init__.py
 | | - my_first_helper_function.py
 | | - my_second_helper_function.py
 | - tests/
 | | - test_my_second_function.py
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - requirements.txt
 | - Dockerfile

以下は後述する v2 と同様です。

  • local.settings.json: ローカルで実行する際に、アプリの設定と接続文字列を格納するために使用する。このファイルは Azure に公開されません。プロジェクトを Azure に発行する時は、関数アプリのアプリ設定にも必要な設定を必ず追加する必要がある。以下は、local.settings.json の記述例になります。
  • requirements.txt: Azure に公開するときにシステムによってインストールされる Python パッケージの一覧が含まれます。
  • host.json: 関数アプリインスタンス内にあるすべての関数に影響する構成オプションが含まれます。このファイルは Azure に公開されます。以下は、host.json の記述例になります。
  • .vscode/: (省略可能) 格納されている Visual Studio Code 構成が含まれます。
  • .venv/: (省略可能) ローカル開発で使用される Python 仮想環境が含まれます。
  • Dockerfile: (省略可能) カスタムコンテナーでプロジェクトを発行するときに使用されます。
  • tests/: (省略可能) 関数アプリのテストケースが含まれます。
  • .funcignore: (省略可能) Azure に発行しないファイルを宣言します。通常、このファイルには、エディター設定を無視する場合は .vscode/、ローカルの Python 仮想環境を無視する場合は .venv/、テストケースを無視する場合は tests/、ローカルアプリの設定を発行しない場合は local.settings.json を含めます。

以下は v2 と異なるファイル群です。

  • <関数ディレクトリ>/: 独自のコードファイルとバインディング構成ファイル function.json を含めます。

※Azure の関数アプリにプロジェクトをデプロイするときは、メインプロジェクトフォルダー <project_root> の内容全体をパッケージに含める必要があります。ただし、フォルダー自体は含めてはいけない。つまり、host.json ファイルはパッケージルートに存在する必要があります。

v2
公開ドキュメントに記載されている推奨フォルダ構造

<project_root>/
 | - .venv/
 | - .vscode/
 | - function_app.py
 | - additional_functions.py
 | - tests/
 | | - test_my_function.py
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - requirements.txt
 | - Dockerfile

以下は先述の v1 と同様です。

  • local.settings.json: ローカルで実行する際に、アプリの設定と接続文字列を格納するために使用する。このファイルは Azure に公開されません。プロジェクトを Azure に発行する時は、関数アプリのアプリ設定にも必要な設定を必ず追加する必要がある。以下は、local.settings.json の記述例になります。
  • requirements.txt: Azure に公開するときにシステムによってインストールされる Python パッケージの一覧が含まれます。
  • host.json: 関数アプリインスタンス内にあるすべての関数に影響する構成オプションが含まれます。このファイルは Azure に公開されます。以下は、host.json の記述例になります。
  • .vscode/: (省略可能) 格納されている Visual Studio Code 構成が含まれます。
  • .venv/: (省略可能) ローカル開発で使用される Python 仮想環境が含まれます。
  • Dockerfile: (省略可能) カスタムコンテナーでプロジェクトを発行するときに使用されます。
  • tests/: (省略可能) 関数アプリのテストケースが含まれます。
  • .funcignore: (省略可能) Azure に発行しないファイルを宣言します。通常、このファイルには、エディター設定を無視する場合は .vscode/、ローカルの Python 仮想環境を無視する場合は .venv/、テストケースを無視する場合は tests/、ローカルアプリの設定を発行しない場合は local.settings.json を含めます。

以下は v1 と異なるファイル群です。

  • function_app.py: すべての関数とそれに関連するトリガーとバインドの場所です。
  • additional_functions.py: (省略可能) ブループリントを介して function_app.py で参照される関数を含む他の Python ファイルです。

※Azure の関数アプリにプロジェクトをデプロイするときは、メインプロジェクトフォルダー <project_root> の内容全体をパッケージに含める必要があります。ただし、フォルダー自体は含めてはいけない。つまり、host.json ファイルはパッケージルートに存在する必要があります。

ブループリントは、コア関数アプリケーションの外部で関数を登録するためにインスタンス化された新しいクラスです。
ブループリントを使用することには次の利点があります。

  • 関数アプリをモジュール型コンポーネントに分割して、複数の Python ファイルで関数を定義し、ファイルごとに異なるコンポーネントに分割できます。
  • 独自の API をビルドして再利用するための、拡張可能なパブリック関数アプリインターフェイスを提供します。

次の例は、http_blueprint.py ファイルで HTTP によってトリガーされる関数が定義されてブループリントオブジェクトに追加され、function_app.py ファイルでブループリントオブジェクトがインポートされて関数が関数アプリに登録される例となります。

http_blueprint.py
import logging 

import azure.functions as func 

bp = func.Blueprint() 

@bp.route(route="default_template") 
def default_template(req: func.HttpRequest) -> func.HttpResponse: 
    logging.info('Python HTTP trigger function processed a request.') 

    name = req.params.get('name') 
    if not name: 
        try: 
            req_body = req.get_json() 
        except ValueError: 
            pass 
        else: 
            name = req_body.get('name') 

    if name: 
        return func.HttpResponse( 
            f"Hello, {name}. This HTTP-triggered function " 
            f"executed successfully.") 
    else: 
        return func.HttpResponse( 
            "This HTTP-triggered function executed successfully. " 
            "Pass a name in the query string or in the request body for a" 
            " personalized response.", 
            status_code=200 
        )
function_app.py
import azure.functions as func 
from http_blueprint import bp

app = func.FunctionApp() 

app.register_functions(bp)

まとめ

Azure Functions で Python を使用する際には、v1 と v1 のプログラミングモデルがあります。
v2 のプログラミングモデルでは、Functions アプリケーションを簡単に作成できるようになり、Functions 特有の概念が少なくなり、代わりに Python の原則が強調されています。
主な改良点としては、Python のデコレートを使用して Functions で必要なトリガーとバインディングが宣言されるようになったり、フォルダ構造がシンプルになったり、ドキュメントが参照しやすくなったなどが挙げられます。

今回の記事が Azure Functions で Python を使用を検討する際の参考になりますと幸いです。
Azure Functions で Python を使用する方法として、更新がありましたら本記事を随時アップデートしていこうと思います。
記載に誤り等がございましたら、指摘いただけますと幸いです🙌🙌🙌
(本記事は、2023/09/04 時点の公開ドキュメントと実際に関数アプリを作成して使用した内容をもとに作成しました。)

参考記事

Discussion