您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

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 应用服务公告存储库。To receive important updates, subscribe to the Azure App Service announcements repository on GitHub.

编程模型Programming model

Azure 函数应是 Python 脚本中处理输入并生成输出的无状态方法。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 存储中检索_ID_中的路由 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这是由 function app 使用的同一存储帐户。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.

若要使用函数的返回值作为输出绑定的值,则绑定的 name 属性应在 function.json 中设置为 $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()

上下文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}'

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。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 命令从 PyPI 安装 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. 如果使用的包需要编译器并且不支持从 PyPI 安装 manylinux 兼容滚轮的包,则发布到 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). 请记住将 <app name> 替换为 Azure 中的函数应用名称。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. 对于大多数绑定,则可以通过创建从相应的类的实例来创建一个模拟的输入的对象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.

例如,下面是函数的 HTTP 触发的模拟测试:For example, following is a mock test of an HTTP triggered function:

# myapp/__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()}')
# 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 HTTP request.
        req = func.HttpRequest(
            method='GET',
            body=None,
            url='/my_function', 
            params={'name': 'Test'})

        # Call the function.
        resp = my_function(req)

        # Check the output.
        self.assertEqual(
            resp.get_body(), 
            '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: