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.

如需 Python 中的獨立函式範例專案,請參閱 Python 函式範例For standalone Function sample projects in Python, see the Python Functions samples.

程式設計模型Programming model

Azure Functions 預期函式在 Python 腳本中是可處理輸入並產生輸出的無狀態方法。Azure Functions expects a function to 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. 您也可以指定替代的進入點You can also specify an alternate entry point.

來自觸發程式和系結的資料會使用函式json檔案中name定義的屬性, 透過方法屬性系結至函式。Data from triggers and bindings is bound to the function via method attributes using the name property defined in the function.json file. 例如, 下面的_函數. 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}!'

您也可以使用 Python 類型注釋,在函式中明確宣告屬性類型和傳回類型。you can also explicitly declare the attribute types and return type in the function using Python type annotations. 這可協助您使用許多 Python 程式碼編輯器所提供的 intellisense 和自動完成功能。This helps you use the intellisense and autocomplete features provided by many Python code editors.

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.

替代進入點Alternate entry point

您可以選擇性地在scriptFile 函數. json檔案中指定和entryPoint屬性,以變更函式的預設行為。You can change the default behavior of a function by optionally specifying the scriptFile and entryPoint properties in the function.json file. 例如, 下列函式會指示執行時間在_main.py_檔案中使用customentry()方法, 做為您的 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",
  "bindings": [
      ...
  ]
}

資料夾結構Folder structure

Python 函式專案的資料夾結構如下列範例所示:The folder structure for a Python Functions project looks like the following example:

 FunctionApp
 | - MyFirstFunction
 | | - __init__.py
 | | - function.json
 | | - example.py
 | - 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

若要參考函數的本機模組,您可以使用相對的匯入語法,如下所示:To reference modules local to a function, you can use the relative import syntax as follows:

from . import example

將函式專案部署至 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. 系統會根據路由 URL 中的_識別碼_從 Azure Blob 儲存體中抓取專案, 並在函式主體中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.

若要產生多個輸出, set()請使用azure.functions.Out介面提供的方法, 將值指派給系結。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
critical(_message_) 在根記錄器上寫入層級為 CRITICAL (重大) 的訊息。Writes a message with level CRITICAL on the root logger.
error(_message_) 在根記錄器上寫入層級為 ERROR (錯誤) 的訊息。Writes a message with level ERROR on the root logger.
warning(_message_) 在根記錄器上寫入層級為 WARNING (警告) 的訊息。Writes a message with level WARNING on the root logger.
info(_message_) 在根記錄器上寫入層級為 INFO (資訊) 的訊息。Writes a message with level INFO on the root logger.
debug(_message_) 在根記錄器上寫入層級為 DEBUG (偵錯) 的訊息。Writes a message with level DEBUG on the root logger.

若要深入瞭解記錄,請參閱監視 Azure FunctionsTo learn more about logging, see Monitor Azure Functions.

HTTP 觸發程式和系結HTTP Trigger and bindings

HTTP 觸發程式定義于 function. jon 檔案中。The HTTP trigger is defined in the function.jon file. name系結的必須符合函式中的具名引數。The name of the binding must match the named parameter in the function. 在先前的範例中,會使用req系結名稱。In the previous examples, a binding name req is used. 這個參數是HttpRequest物件,而且會傳回HttpResponse物件。This parameter is an HttpRequest object, and an HttpResponse object is returned.

您可以從HttpRequest物件取得要求標頭、查詢參數、路由參數和訊息內文。From the HttpRequest object, you can get request headers, query parameters, route parameters, and the message body.

下列範例來自Python 的 HTTP 觸發程式範本The following example is from the HTTP trigger template for Python.

def main(req: func.HttpRequest) -> func.HttpResponse:
    headers = {"my-http-header": "some-value"}

    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}!", headers=headers)
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             headers=headers, status_code=400
        )

在此函數中,會從name HttpRequest物件的params參數取得查詢參數的值。In this function, the value of the name query parameter is obtained from the params parameter of the HttpRequest object. 使用get_json方法讀取 JSON 編碼的訊息本文。The JSON-encoded message body is read using the get_json method.

同樣status_code地,您可以針對傳回headersHttpResponse物件中的回應訊息,設定和。Likewise, you can set the status_code and headers for the response message in the returned HttpResponse object.

非同步處理Async

建議您使用async def語句, 將您的 Azure Function 撰寫為非同步協同程式。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 ()函式是同步的(沒有辨識符號),我們會自動在asyncio執行緒集區中執行函數。If the main() function is synchronous (no 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()

內容Context

若要在執行期間取得函數的調用內容, 請在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}'

內容類具有下列方法: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

環境變數Environment variables

在函數中,應用程式設定(例如服務連接字串)在執行期間會公開為環境變數。In Functions, application settings, such as service connection strings, are exposed as environment variables during execution. 您可以藉由import os宣告,然後setting = os.environ["setting-name"]使用來存取這些設定。You can access these settings by declaring import os and then using, setting = os.environ["setting-name"].

下列範例會取得應用程式設定,並使用名為myAppSetting的機碼:The following example gets the application setting, with the key named myAppSetting:

import logging
import os
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:

    # Get the setting named 'myAppSetting'
    my_app_setting_value = os.environ["myAppSetting"]
    logging.info(f'My app setting value:{my_app_setting_value}')

就本機開發而言,應用程式設定會保留在本機的設定 json 檔案中For local development, application settings are maintained in the local.settings.json file.

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

當您準備好要發行時, 請確定您的所有相依性都列在 [需求 .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. Azure Functions 可以從遠端建立這些相依性。Azure Functions can remotely build these dependencies.

從發行排除的專案檔和資料夾(包括虛擬環境資料夾)會列在 funcignore 檔案中。Project files and folders that are excluded from publishing, including the virtual environment folder, are listed in the .funcignore file.

若要部署至 Azure 並執行遠端組建,請使用下列命令:To deploy to Azure and perform a remote build, use the following command:

func azure functionapp publish <app name> --build remote

如果您不是使用遠端組建,並使用需要編譯器的套件,且不支援從 PyPI 安裝許多 Linux 相容的輪,則發行至 Azure 而不在本機建立,將會因下列錯誤而失敗:If you're not using remote build, and using a package that requires a compiler and does not support the installation of many Linux-compatible wheels from PyPI, publishing to Azure without building locally 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 build locally 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 will then build and install the required modules from source distribution, before packaging them up for final deployment to Azure.

若要建立您的相依性,並使用持續傳遞(CD)系統發佈,請使用 Azure PipelinesTo build your dependencies and publish using a continuous delivery (CD) system, use Azure Pipelines.

單元測試Unit Testing

以 Python 撰寫的函式可以使用標準測試架構來測試, 就像其他 Python 程式碼一樣。Functions written in Python can be tested like other Python code using standard testing frameworks. 對於大部分的系結, 您可以從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 觸發函式的模擬測試: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.

跨原始資源共用Cross-origin resource sharing

Azure Functions 支援跨原始來源資源分享(CORS)。Azure Functions supports cross-origin resource sharing (CORS). CORS 會在入口網站中以及透過Azure CLI進行設定。CORS is configured in the portal and through the Azure CLI. CORS 允許的原始來源清單適用于函數應用層級。The CORS allowed origins list applies at the function app level. 在啟用 CORS 的情況下, Access-Control-Allow-Origin回應會包含標頭。With CORS enabled, responses include the Access-Control-Allow-Origin header. 如需詳細資訊,請參閱 跨原始來源資源分享(英文)。For more information, see Cross-origin resource sharing.

Python 函式應用程式目前不支援允許的原始來源清單。The allowed origins list isn't currently supported for Python function apps. 由於這項限制,您必須在 HTTP 函Access-Control-Allow-Origin式中明確設定標頭,如下列範例所示:Because of this limitation, you must expressly set the Access-Control-Allow-Origin header in your HTTP functions, as shown in the following example:

def main(req: func.HttpRequest) -> func.HttpResponse:

    # Define the allow origin headers.
    headers = {"Access-Control-Allow-Origin": "https://contoso.com"}

    # Set the headers in the response.
    return func.HttpResponse(
            f"Allowed origin '{headers}'.",
            headers=headers, status_code=200
    )

請確定您也更新了函數. json,以支援 OPTIONS HTTP 方法:Make sure that you also update your function.json to support the OPTIONS HTTP method:

    ...
      "methods": [
        "get",
        "post",
        "options"
      ]
    ...

Chrome 瀏覽器會使用這個方法來協調允許的原始來源清單。This method is used by the Chrome browser to negotiate the allowed origins list.

後續步驟Next steps

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