Azure Functions Python 開發人員指南Azure Functions Python developer guide

本文是使用 Python 開發 Azure Functions 的簡介。This article is an introduction to developing Azure Functions using Python. 本文假設您已閱讀過下列 Azure Functions 開發人員指南The content below assumes that you've already read the Azure Functions developers guide.

注意

適用於 Azure Functions 的 Python 目前為預覽版。Python for Azure Functions is currently in preview. 若要接收重要更新,請在 GitHub 上訂閱 Azure App Service 通知存放庫。To receive important updates, subscribe to the Azure App Service announcements repository on GitHub.

程式設計模型Programming model

Python 指令碼中的 Azure 函式應該是無狀態方法,處理輸入及產生輸出。An Azure Function should be a stateless method in your Python script that processes input and produces output. 根據預設,執行階段會預期要實作為通用的方法呼叫的方法main()__init__.py檔案。By default, the runtime expects the method to be implemented as a global method called main() in the __init__.py file.

您可以變更預設組態,藉由指定scriptFileentryPoint中的屬性function.json檔案。You can change the default configuration by specifying the scriptFile and entryPoint properties in the function.json file. 例如, _function.json_下方會告訴執行階段使用customentry()中的方法_main.py_檔案中,作為您的 Azure 函式的進入點。For example, the function.json below tells the runtime to use the customentry() method in the main.py file, as the entry point for your Azure Function.

{
  "scriptFile": "main.py",
  "entryPoint": "customentry",
  ...
}

從觸發程序和繫結的資料透過繫結至函式使用的方法屬性name中所定義的屬性function.json檔案。Data from triggers and bindings is bound to the function via method attributes using the name property defined in the function.json file. 例如, _function.json_以下說明名為 HTTP 要求所觸發的簡單函式req:For example, the function.json below describes a simple function triggered by an HTTP request named req:

{
  "bindings": [
    {
      "name": "req",
      "direction": "in",
      "type": "httpTrigger",
      "authLevel": "anonymous"
    },
    {
      "name": "$return",
      "direction": "out",
      "type": "http"
    }
  ]
}

__init__.py 檔案包含下列函式程式碼:The __init__.py file contains the following function code:

def main(req):
    user = req.params.get('user')
    return f'Hello, {user}!'

(選擇性) 若要利用 intellisense 和程式碼編輯器所提供的自動完成功能,您可以也宣告屬性型別和中使用 Python 型別註釋函式的傳回類型。Optionally, to leverage the intellisense and auto-complete features provided by your code editor, you can also declare the attribute types and return type in the function using Python type annotations.

import azure.functions


def main(req: azure.functions.HttpRequest) -> str:
    user = req.params.get('user')
    return f'Hello, {user}!'

請使用 azure.functions.* 套件中所包含的 Python 註釋,以將輸入和輸出繫結至方法。Use the Python annotations included in the azure.functions.* package to bind input and outputs to your methods.

資料夾結構Folder structure

Python 函式專案的資料夾結構看起來如下:The folder structure for a Python Functions project looks like the following:

 FunctionApp
 | - MyFirstFunction
 | | - __init__.py
 | | - function.json
 | - MySecondFunction
 | | - __init__.py
 | | - function.json
 | - SharedCode
 | | - myFirstHelperFunction.py
 | | - mySecondHelperFunction.py
 | - host.json
 | - requirements.txt

其中有一個可用來設定函數應用程式的共用 host.json 檔案。There's a shared host.json file that can be used to configure the function app. 每個函式都具有本身的程式碼檔案和繫結設定檔 (function.json)。Each function has its own code file and binding configuration file (function.json).

共用程式碼應該放在個別的資料夾。Shared code should be kept in a separate folder. 若要參考 SharedCode 資料夾中的模組,您可以使用下列語法:To reference modules in the SharedCode folder, you can use the following syntax:

from __app__.SharedCode import myFirstHelperFunction

將函式專案部署至您的函式應用程式,在 Azure 中的整個內容時FunctionApp資料夾應該會包含在封裝,而不是資料夾本身。When deploying a Function project to your function app in Azure, the entire content of the FunctionApp folder should be included in the package, but not the folder itself.

觸發程序和輸入Triggers and Inputs

在 Azure Functions 中輸入會分成兩個類別:觸發程序輸入和額外的輸入。Inputs are divided into two categories in Azure Functions: trigger input and additional input. 儘管它們是在不同function.json檔案中,使用方式中有相同的 Python 程式碼。Although they are different in the function.json file, usage is identical in Python code. 中的值對應的連接字串或觸發程序和輸入來源的祕密local.settings.json檔案時,在本機執行,並在 Azure 中執行時的應用程式設定。Connection strings or secrets for trigger and input sources map to values in the local.settings.json file when running locally, and the application settings when running in Azure.

例如,下列程式碼會示範兩者之間的差異:For example, the following code demonstrates the difference between the two:

// function.json
{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "req",
      "direction": "in",
      "type": "httpTrigger",
      "authLevel": "anonymous",
      "route": "items/{id}"
    },
    {
      "name": "obj",
      "direction": "in",
      "type": "blob",
      "path": "samples/{id}",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
// local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsStorage": "<azure-storage-connection-string>"
  }
}
# __init__.py
import azure.functions as func
import logging


def main(req: func.HttpRequest,
         obj: func.InputStream):

    logging.info(f'Python HTTP triggered function processed: {obj.read()}')

叫用此函式時,HTTP 要求會以 req 形式傳遞至函式。When the function is invoked, the HTTP request is passed to the function as req. 項目會從 Azure Blob 儲存體,以擷取_識別碼_中的路由 URL,並可做為obj函式主體中。An entry will be retrieved from the Azure Blob Storage based on the ID in the route URL and made available as obj in the function body. 在此儲存體帳戶指定的連接字串位於AzureWebJobsStorage即函式應用程式所使用的相同儲存體帳戶。Here the storage account specified is the connection string found in AzureWebJobsStorage which is the same storage account used by the function app.

outputsOutputs

輸出可以使用傳回值和輸出參數來表示。Output can be expressed both in return value and output parameters. 如果只有一個輸出,我們建議使用傳回的值。If there's only one output, we recommend using the return value. 若為多個輸出,您必須使用輸出參數。For multiple outputs, you'll have to use output parameters.

若要使用函式的傳回值作為輸出繫結的值,應該將 function.json 中的繫結 name 屬性設定為 $returnTo use the return value of a function as the value of an output binding, the name property of the binding should be set to $return in function.json.

若要產生多個輸出,請使用 azure.functions.Out 介面提供的 set() 方法為繫結指派值。To produce multiple outputs, use the set() method provided by the azure.functions.Out interface to assign a value to the binding. 例如,下列函式可以將訊息推送至佇列,同時也會傳回 HTTP 回應。For example, the following function can push a message to a queue and also return an HTTP response.

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "req",
      "direction": "in",
      "type": "httpTrigger",
      "authLevel": "anonymous"
    },
    {
      "name": "msg",
      "direction": "out",
      "type": "queue",
      "queueName": "outqueue",
      "connection": "AzureWebJobsStorage"
    },
    {
      "name": "$return",
      "direction": "out",
      "type": "http"
    }
  ]
}
import azure.functions as func


def main(req: func.HttpRequest,
         msg: func.Out[func.QueueMessage]) -> str:

    message = req.params.get('body')
    msg.set(message)
    return message

記錄Logging

可以透過函式應用程式中的根 logging 處理常式來存取 Azure Functions 執行階段記錄器。Access to the Azure Functions runtime logger is available via a root logging handler in your function app. 這個記錄器會繫結至 Application Insights,並可讓您將函式執行期間遇到的警告和錯誤加上旗標。This logger is tied to Application Insights and allows you to flag warnings and errors encountered during the function execution.

下列範例在透過 HTTP 觸發程序叫用函式時,會記錄一則資訊訊息。The following example logs an info message when the function is invoked via an HTTP trigger.

import logging


def main(req):
    logging.info('Python HTTP trigger function processed a request.')

其他的記錄方法可讓您在不同追蹤層級寫入主控台記錄中︰Additional logging methods are available that let you write to the console at different trace levels:

方法Method 說明Description
logging.critical(message)logging.critical(message) 在根記錄器上寫入層級為 CRITICAL (重大) 的訊息。Writes a message with level CRITICAL on the root logger.
logging.error(message)logging.error(message) 在根記錄器上寫入層級為 ERROR (錯誤) 的訊息。Writes a message with level ERROR on the root logger.
logging.warning(message)logging.warning(message) 在根記錄器上寫入層級為 WARNING (警告) 的訊息。Writes a message with level WARNING on the root logger.
logging.info(message)logging.info(message) 在根記錄器上寫入層級為 INFO (資訊) 的訊息。Writes a message with level INFO on the root logger.
logging.debug(message)logging.debug(message) 在根記錄器上寫入層級為 DEBUG (偵錯) 的訊息。Writes a message with level DEBUG on the root logger.

非同步處理Async

我們建議您撰寫您的 Azure 函式,以非同步的協同程式使用async def陳述式。We recommend that you write your Azure Function as an asynchronous coroutine using the async def statement.

# Will be run with asyncio directly


async def main():
    await some_nonblocking_socket_io_op()

如果是同步的 main () 函式 (沒有async辨識符號) 我們會自動執行函式asyncio執行緒集區。If the main() function is synchronous (no async qualifier) we automatically run the function in an asyncio thread-pool.

# Would be run in an asyncio thread-pool


def main():
    some_blocking_socket_io()

ContextContext

若要在執行期間取得函式的引動內容,請在其簽章中包含 context引數。To get the invocation context of a function during execution, include the context argument in its signature.

例如:For example:

import azure.functions


def main(req: azure.functions.HttpRequest,
         context: azure.functions.Context) -> str:
    return f'{context.invocation_id}'

Context 類別具有下列方法:The Context class has the following methods:

function_directory
函式執行所在的目錄。The directory in which the function is running.

function_name
函式的名稱。Name of the function.

invocation_id
目前函式引動的識別碼。ID of the current function invocation.

全域變數Global variables

不保證您的應用程式的狀態將會保留供日後執行。It is not guaranteed that the state of your app will be preserved for future executions. 不過,Azure Functions 執行階段通常會重複使用相同的應用程式的多個執行的相同程序。However, the Azure Functions runtime often reuses the same process for multiple executions of the same app. 若要快取的昂貴的計算結果,請將它宣告為全域變數中。In order to cache the results of an expensive computation, declare it as a global variable.

CACHED_DATA = None


def main(req):
    global CACHED_DATA
    if CACHED_DATA is None:
        CACHED_DATA = load_json()

    # ... use CACHED_DATA in code

Python 版本和套件管理Python version and package management

Azure Functions 目前僅支援 Python 3.6.x (官方 CPython 發佈)。Currently, Azure Functions only supports Python 3.6.x (official CPython distribution).

使用 Azure Functions Core Tools 或 Visual Studio Code 在本機進行開發時,將所需的套件名稱和版本新增到 requirements.txt 檔案,並使用 pip 進行安裝。When developing locally using the Azure Functions Core Tools or Visual Studio Code, add the names and versions of the required packages to the requirements.txt file and install them using pip.

例如,可以使用下列要求和 pip 命令從 PyPl 安裝 requests 套件。For example, the following requirements file and pip command can be used to install the requests package from PyPI.

requests==2.19.1
pip install -r requirements.txt

發行到 AzurePublishing to Azure

當您準備好發佈時,請確定所有的相依性所述requirements.txt檔案,這是您的專案目錄的根目錄中找到。When you're ready to publish, make sure that all your dependencies are listed in the requirements.txt file, which is located at the root of your project directory. 如果您正在使用需要編譯器且不支援從 PyPl 安裝多版 Linux 相容的套件,則發行至 Azure 會失敗,並發生下列錯誤:If you're using a package that requires a compiler and does not support the installation of manylinux-compatible wheels from PyPI, publishing to Azure will fail with the following error:

There was an error restoring dependencies.ERROR: cannot install <package name - version> dependency: binary dependencies without wheels are not supported.  
The terminal process terminated with exit code: 1

若要自動建置和設定必要的二進位檔,請在本機電腦上安裝 Docker,並執行下列命令以使用 Azure Functions Core Tools (func) 來發行。To automatically build and configure the required binaries, install Docker on your local machine and run the following command to publish using the Azure Functions Core Tools (func). 在 Azure 中,請記得以您的函式應用程式名稱取代 <app name>Remember to replace <app name> with the name of your function app in Azure.

func azure functionapp publish <app name> --build-native-deps

基本上,Core Tools 會使用 docker 將 mcr.microsoft.com/azure-functions/python 映像作為本機電腦上的容器。Underneath the covers, Core Tools will use docker to run the mcr.microsoft.com/azure-functions/python image as a container on your local machine. 接著,它會利用此環境從來源發佈建置並安裝必要的模組,再將其封裝以最終部署至 Azure。Using this environment, it'll then build and install the required modules from source distribution, before packaging them up for final deployment to Azure.

若要如何建置您的相依性和發行使用持續傳遞 (CD) 系統中,使用 Azure DevOps 管線To build your dependencies and publish using a continuous delivery (CD) system, use Azure DevOps Pipelines.

單元測試Unit Testing

以 Python 撰寫的函式可以像其他的 Python 程式碼,使用標準的測試架構測試。Functions written in Python can be tested like other Python code using standard testing frameworks. 對於大部分的繫結,就可以建立從適當的類別的執行個體來建立模擬 (mock) 的輸入的物件azure.functions封裝。For most bindings, it's possible to create a mock input object by creating an instance of an appropriate class from the azure.functions package. 由於 azure.functions 封裝不是立即可用,請務必將它透過安裝程式requirements.txt檔案中所述Python 版本和套件管理上一節。Since the azure.functions package is not immediately available, be sure to install it via your requirements.txt file as described in Python version and package management section above.

例如,以下是 HTTP 觸發函式的模擬 (mock) 測試:For example, following is a mock test of an HTTP triggered function:

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

def my_function(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}")
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             status_code=400
        )
# myapp/test_httpfunc.py
import unittest

import azure.functions as func
from httpfunc import my_function


class TestFunction(unittest.TestCase):
    def test_my_function(self):
        # Construct a mock HTTP request.
        req = func.HttpRequest(
            method='GET',
            body=None,
            url='/api/HttpTrigger',
            params={'name': 'Test'})

        # Call the function.
        resp = my_function(req)

        # Check the output.
        self.assertEqual(
            resp.get_body(),
            b'Hello Test',
        )

以下是另一個範例中的,使用佇列觸發函式:Here is another example, with a queue triggered function:

# myapp/__init__.py
import azure.functions as func


def my_function(msg: func.QueueMessage) -> str:
    return f'msg body: {msg.get_body().decode()}'
# myapp/test_func.py
import unittest

import azure.functions as func
from . import my_function


class TestFunction(unittest.TestCase):
    def test_my_function(self):
        # Construct a mock Queue message.
        req = func.QueueMessage(
            body=b'test')

        # Call the function.
        resp = my_function(req)

        # Check the output.
        self.assertEqual(
            resp,
            'msg body: test',
        )

已知問題和常見問題集Known issues and FAQ

所有已知問題和功能要求則會使用 GitHub 問題清單追蹤。All known issues and feature requests are tracked using GitHub issues list. 如果您遇到問題,但在 GitHub 中卻找不到此問題,請開啟新的問題,並包含問題的詳細說明。If you run into a problem and can't find the issue in GitHub, open a new issue and include a detailed description of the problem.

後續步驟Next steps

如需詳細資訊,請參閱下列資源:For more information, see the following resources: