Azure Functions Python 开发人员指南

本文介绍如何使用 Python 进行 Azure Functions 开发。 假设你已阅读 Azure Functions 开发人员指南

作为 Python 开发人员,你可能还会对下列某篇文章感兴趣:

入门 概念 场景/示例

注意

虽然可以在 Windows 上本地开发基于 Python 的函数,但仅当 Python 函数在 Linux 上运行时,它们才受 Azure 的支持。 请参阅支持的操作系统/运行时组合列表。

编程模型

Azure Functions 要求函数是 Python 脚本中处理输入并生成输出的无状态方法。 默认情况下,运行时预期该方法在 _init_ .py 文件中作为名为 main() 的全局方法实现。 还可以指定备用入口点

来自触发器和绑定的数据使用在 function.json 文件中定义的 name 属性,通过方法特性绑定到函数。 例如,以下 function.json 文件描述一个由名为 req 的 HTTP 请求触发的简单函数:

{
    "scriptFile": "__init__.py",
    "bindings": [
        {
            "authLevel": "function",
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": [
                "get",
                "post"
            ]
        },
        {
            "type": "http",
            "direction": "out",
            "name": "$return"
        }
    ]
}

根据这一定义,包含函数代码的 _init_ .py 文件可能类似于以下示例:

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

还可以使用 Python 类型注释在函数中显式声明属性类型和返回类型。 此操作有助于使用许多 Python 代码编辑器提供的 IntelliSense 和自动完成功能。

import azure.functions


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

使用 azure.functions.* 包中附带的 Python 注释将输入和输出绑定到方法。

备用入口点

可以选择在 function.json 文件中指定 scriptFileentryPoint 属性来更改函数的默认行为。 例如,以下 function.json 文件指示运行时使用 main.py 文件中的 customentry() 方法作为函数的入口点:

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

文件夹结构

Python 中 Azure Functions 项目的建议文件夹结构如以下示例所示:

 <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

主项目文件夹 (<project_root>) 可以包含以下文件:

  • local.settings.json:当函数在本地运行时用于存储应用设置和连接字符串。 此文件不会发布到 Azure。 若要了解详细信息,请参阅本地设置文件
  • requirements.txt:包含在发布到 Azure 时系统安装的 Python 包列表。
  • host.json:包含在函数应用实例中影响所有函数的配置选项。 此文件将发布到 Azure。 当函数在本地运行时,并非所有选项都受支持。 有关详细信息,请参阅 host.json 参考
  • .vscode/:(可选)包含存储的 Visual Studio Code 配置。 若要了解详细信息,请参阅用户和工作区设置
  • .venv/:(可选)包含用于本地开发的 Python 虚拟环境。
  • Dockerfile:(可选)在自定义容器中发布项目时使用。
  • tests/:(可选)包含函数应用的测试用例。
  • .funcignore:(可选)声明不应发布到 Azure 的文件。 通常,此文件包含 .vscode/ 以忽略编辑器设置,包含 .venv/ 以忽略本地 Python 虚拟环境,包含 tests/ 以忽略测试用例,包含 local.settings.json 以阻止发布本地应用设置。

每个函数都有自己的代码文件和绑定配置文件 (function.json)。

在 Azure 中将项目部署到函数应用时,主项目 (<project_root>) 文件夹的整个内容应包含在包中,但不包含该文件夹本身。 这意味着 host.json 应位于包根目录中。 建议你在一个文件夹中维护测试以及其他函数。 在此示例中,该文件夹为 tests/。 有关详细信息,请参阅单元测试

导入行为

可以使用绝对引用和相对引用在函数代码中导入模块。 根据前面所示的文件夹结构,以下导入在函数文件 <project_root>\my_first_function\__init__.py 中工作:

from shared_code import my_first_helper_function #(absolute)
import shared_code.my_second_helper_function #(absolute)
from . import example #(relative)

注意

使用绝对导入语法时,shared_code/ 文件夹需要包含 __init__.py 文件以将其标记为 Python 包。

以下 __app__ 导入和非顶级相对导入已弃用。 静态类型检查器和 Python 测试框架不支持这种导入。

from __app__.shared_code import my_first_helper_function #(deprecated __app__ import)
from ..shared_code import my_first_helper_function #(deprecated beyond top-level relative import)

触发器和输入

在 Azure Functions 中,输入分为两种类别:触发器输入和其他绑定输入。 虽然它们在 function.json 文件中并不相同,但它们在 Python 代码中的使用方法却是相同的。 当函数在本地运行时,触发器和输入源所需的连接字符串或机密将保留在 local.settings.json 文件中的 Values 集合中。 当函数在 Azure 中运行时,这些连接字符串或机密将安全地存储为应用程序设置

以下示例代码演示两者之间的差异:

// 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 传递给函数。 将基于路由 URL 中的 ID 从 Azure Blob 存储检索一个条目,并在函数体中用作 obj。 此处指定的存储帐户是在 AzureWebJobsStorage 应用设置中找到的连接字符串,也是函数应用使用的同一个存储帐户。

Outputs

输出可以在返回值和输出参数中表示。 如果只有一个输出,则建议使用返回值。 对于多个输出,必须使用输出参数。

若要使用函数的返回值作为输出绑定的值,请在 function.json 中将绑定的 name 属性设置为 $return

若要生成多个输出,请使用 azure.functions.Out 接口提供的 set() 方法将值分配给绑定。 例如,以下函数可将消息推送到队列并返回 HTTP 响应:

{
  "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 处理程序来访问 Azure Functions 运行时记录器。 此记录器绑定到 Application Insights,并允许标记在函数执行期间遇到的警告和错误。

以下示例在通过 HTTP 触发器调用函数时记录信息消息:

import logging


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

有更多日志记录方法可用于在不同跟踪级别向控制台进行写入:

方法 说明
critical(_message_) 在根记录器中写入具有 CRITICAL 级别的消息。
error(_message_) 在根记录器中写入具有 ERROR 级别的消息。
warning(_message_) 在根记录器中写入具有 WARNING 级别的消息。
info(_message_) 在根记录器中写入具有 INFO 级别的消息。
debug(_message_) 在根记录器中写入具有 DEBUG 级别的消息。

若要详细了解日志记录,请参阅监视 Azure Functions

记录自定义遥测数据

默认情况下,Azure Functions 运行时会收集函数生成的日志和其他遥测数据。 此遥测最终会作为 Application Insights 中的跟踪。 默认情况下,触发器和绑定还会收集某些 Azure 服务的请求和依赖项遥测数据。

若要在绑定之外收集自定义请求和自定义依赖项遥测数据,可以使用 OpenCensus Python 扩展。 Azure Functions 扩展将自定义遥测数据发送到 Application Insights 实例。 可以在 OpenCensus 存储库中找到受支持的扩展的列表。

注意

若要使用 OpenCensus Python 扩展,需要通过将 PYTHON_ENABLE_WORKER_EXTENSIONS 设置为 1,在函数应用中启用 Python 辅助角色扩展。 还需要切换为使用 Application Insights 连接字符串,方法是将 APPLICATIONINSIGHTS_CONNECTION_STRING 设置添加到应用程序设置(如果不存在)。

// requirements.txt
...
opencensus-extension-azure-functions
opencensus-ext-requests
import json
import logging

import requests
from opencensus.extension.azure.functions import OpenCensusExtension
from opencensus.trace import config_integration

config_integration.trace_integrations(['requests'])

OpenCensusExtension.configure()

def main(req, context):
    logging.info('Executing HttpTrigger with OpenCensus extension')

    # You must use context.tracer to create spans
    with context.tracer.span("parent"):
        response = requests.get(url='http://example.com')

    return json.dumps({
        'method': req.method,
        'response': response.status_code,
        'ctx_func_name': context.function_name,
        'ctx_func_dir': context.function_directory,
        'ctx_invocation_id': context.invocation_id,
        'ctx_trace_context_Traceparent': context.trace_context.Traceparent,
        'ctx_trace_context_Tracestate': context.trace_context.Tracestate,
        'ctx_retry_context_RetryCount': context.retry_context.retry_count,
        'ctx_retry_context_MaxRetryCount': context.retry_context.max_retry_count,
    })

HTTP 触发器和绑定

HTTP 触发器在 function.json 文件中定义。 绑定的 name 参数必须与函数中的命名参数匹配。

前面的示例使用绑定名称 req。 此参数是 HttpRequest 对象,并返回 HttpResponse 对象。

HttpRequest 对象中,可以获取请求标头、查询参数、路由参数和消息正文。

以下示例取自适用于 Python 的 HTTP 触发器模板

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 参数获取。 JSON 编码的消息正文使用 get_json 方法来读取。

同样,可以在返回的 HttpResponse 对象中为响应消息设置 status_codeheaders 信息。

Web 框架

可以将与 WSGI 和 ASGI 兼容的框架(如 Flask 和 FastAPI)与 HTTP 触发的 Python 函数结合使用。 本部分介绍如何修改函数以支持这些框架。

首先,必须更新 function.json 文件以在 HTTP 触发器中包含 route,如以下示例中所示:

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
       "authLevel": "anonymous",
       "type": "httpTrigger",
       "direction": "in",
       "name": "req",
       "methods": [
           "get",
           "post"
       ],
       "route": "{*route}"
    },
    {
       "type": "http",
       "direction": "out",
       "name": "$return"
    }
  ]
}

还必须更新 host.json 文件以包含 HTTP routePrefix 值,如以下示例中所示:

{
  "version": "2.0",
  "logging": 
  {
    "applicationInsights": 
    {
      "samplingSettings": 
      {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": 
  {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[2.*, 3.0.0)"
  },
  "extensions": 
  {
    "http": 
    {
        "routePrefix": ""
    }
  }
}

根据框架使用的接口更新 Python 代码文件 init.py。 下面的示例展示了 ASGI 处理程序方法或 Flask 的 WSGI 包装器方法:

app=fastapi.FastAPI()

@app.get("hello/{name}")
async def get_name(
  name: str,):
  return {
      "name": name,}

def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    return AsgiMiddleware(app).handle(req, context)

缩放和性能

有关 Python 函数应用的缩放和性能最佳做法,请参阅在 Azure Functions 中提高 Python 应用的吞吐量性能

上下文

若要在执行过程中获取函数的调用上下文,请在其签名中包含 context 参数。

例如:

import azure.functions


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

Context 类具有以下字符串属性:

  • function_directory:在其中运行函数的目录。

  • function_name:函数的名称。

  • invocation_id:当前函数调用的 ID。

  • trace_context:分布式跟踪的上下文。 有关详细信息,请参阅 W3C 网站上的 Trace Context(跟踪上下文)。

  • retry_context:函数的重试上下文。

全局变量

应用的状态是否将保留,以供将来执行使用,这一点不能保证。 但是,Azure Functions 运行时通常会为同一应用的多次执行重复使用同一进程。 若要缓存高开销计算的结果,请将其声明为全局变量:

CACHED_DATA = None


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

    # ... use CACHED_DATA in code

环境变量

在 Azure Functions 中,服务连接字符串等应用程序设置在执行过程中将公开为环境变量。 在代码中访问这些设置有两种主要方法:

方法 说明
os.environ["myAppSetting"] 尝试根据键名获取应用程序设置。 失败时引发错误。
os.getenv("myAppSetting") 尝试根据键名获取应用程序设置。 失败时返回 null

这两种方法都需要声明 import os

以下示例使用名为 myAppSetting 的键通过 os.environ["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}')

对于本地开发,应用程序设置在 local.settings.json 文件中维护

Python 版本

Azure Functions 支持以下 Python 版本。 这些版本为官方 Python 发行版。

Functions 版本 Python 版本
4.x 3.9
3.8
3.7
3.x 3.9
3.8
3.7
3.6
2.x 3.7
3.6

若要在 Azure 中创建函数应用时请求特定的 Python 版本,请使用 az functionapp create 命令的 --runtime-version 选项。 --functions-version 选项设置 Azure Functions 运行时版本。

更改 Python 版本

若要将 Python 函数应用设置为特定的语言版本,需要在站点配置中的 linuxFxVersion 字段内指定语言以及语言版本。 例如,若要将 Python 应用更改为使用 Python 3.8,请将 linuxFxVersion 设置为 python|3.8

若要详细了解 Azure Functions 运行时支持策略,请参阅语言运行时支持策略

可以在 Azure CLI 中使用 az functionapp config show 命令查看和设置 linuxFxVersion。 将 <function_app> 替换为你的函数应用的名称。 请将 <my_resource_group> 替换为函数应用的资源组名称。

az functionapp config show --name <function_app> \
--resource-group <my_resource_group>

在以下输出中可以看到 linuxFxVersion,为清晰起见,该输出已截断:

{
  ...
  "kind": null,
  "limits": null,
  "linuxFxVersion": <LINUX_FX_VERSION>,
  "loadBalancing": "LeastRequests",
  "localMySqlEnabled": false,
  "location": "China North 2",
  "logsDirectorySizeLimit": 35,
   ...
}

可以使用 az functionapp config set 命令更新函数应用中的 linuxFxVersion 设置。 在以下代码中:

  • <FUNCTION_APP> 替换为你的函数应用的名称。
  • 请将 <RESOURCE_GROUP> 替换为函数应用的资源组名称。
  • 请将 <LINUX_FX_VERSION> 替换为要使用的 Python 版本并加上前缀 python|。 例如:python|3.9
az functionapp config set --name <FUNCTION_APP> \
--resource-group <RESOURCE_GROUP> \
--linux-fx-version <LINUX_FX_VERSION>

可以在使用 az login 登录后,在本地使用 Azure CLI 运行该命令。

在更改站点配置后,函数应用将会重启。

本地 Python 版本

在本地运行时,Azure Functions Core Tools 会使用可用的 Python 版本。

包管理

在使用 Azure Functions Core Tools 或 Visual Studio Code 进行本地开发时,将所需包的名称和版本添加到 requirements.txt 文件并使用 pip 安装它们。

例如,可以使用以下 requirements 文件和 pip 命令从 PyPI 安装 requests 包:

requests==2.19.1
pip install -r requirements.txt

发布到 Azure

准备好进行发布时,确保所有公开发布的依赖项都在 requirements.txt 文件中列出。 此文件位于项目目录的根目录中。

还可以在项目的根目录中找到从发布中排除的项目文件和文件夹,包括虚拟环境文件夹。

支持使用三个生成操作将 Python 项目发布到 Azure:远程生成、本地生成以及使用自定义依赖项生成。

还可使用 Azure Pipelines 生成依赖项并使用持续交付 (CD) 发布。

远程生成

使用远程生成时,服务器上还原的依赖项和本机依赖项与生产环境匹配。 这导致要上传的部署包较小。 在 Windows 上开发 Python 应用时使用远程生成。 如果你的项目具有自定义依赖项,可使用具有额外索引 URL 的远程生成

依赖项根据 requirements.txt 文件的内容远程获取。 远程生成是推荐的生成方法。 默认情况下,使用以下 func azure functionapp publish 命令将 Python 项目发布到 Azure 时,Azure Functions Core Tools 会请求远程生成。 请将 <APP_NAME> 替换为 Azure 中你的函数应用名称。

func azure functionapp publish <APP_NAME>

默认情况下,Visual Studio Code 的 Azure Functions 扩展还会请求远程生成。

本地生成

依赖项根据 requirements.txt 文件的内容在本地获取。 可使用以下 func azure functionapp publish 命令通过本地生成进行发布,从而防止远程生成。 请将 <APP_NAME> 替换为 Azure 中你的函数应用名称。

func azure functionapp publish <APP_NAME> --build local

使用 --build local 选项时,将从 requirements.txt 文件中读取项目依赖项。 将在本地下载并安装这些依赖包。 项目文件和依赖项从本地计算机部署到 Azure。 这会导致将较大的部署包上传到 Azure。 如果无法使用 Core Tools 获取 requirements.txt 文件,则必须使用自定义依赖项选项进行发布。

在 Windows 上进行本地开发时,不建议使用本地生成。

自定义依赖项

如果项目的依赖项在 Python 包索引中找不到,可通过两种方式生成该项目。

具有额外索引 URL 的远程生成

如果包可以从可访问的自定义包索引中获取,请使用远程生成。 在发布之前,请务必创建一个 名为 PIP_EXTRA_INDEX_URL 的应用设置。 此设置的值是自定义包索引的 URL。 使用此设置可告诉远程生成结合 --extra-index-url 选项运行 pip install。 若要了解详细信息,请参阅 Python pip install 文档

还可将基本身份验证凭据与额外的包索引 URL 结合使用。 若要了解详细信息,请参阅 Python 文档中的基本身份验证凭据

注意

如果需要从默认值 https://pypi.org/simple 更改 Python 包索引器的基 URL,可以通过创建一个应用设置(名为 PIP_INDEX_URL,指向其他包索引 URL)来完成。 与 PIP_EXTRA_INDEX_URL 一样,PIP_INDEX_URL 是一个特定于 pip 的应用程序设置,用于更改要使用的 pip 源。

安装本地包

如果项目使用未公开发布的包,你可以通过将这些包放在 __app__/.python_packages 目录中,使其可供应用使用。 发布之前,运行以下命令以在本地安装依赖项:

pip install  --target="<PROJECT_DIR>/.python_packages/lib/site-packages"  -r requirements.txt

使用自定义依赖项时,请使用以下 --no-build 发布选项,因为你已将依赖项安装到项目文件夹中。 请将 <APP_NAME> 替换为 Azure 中你的函数应用名称。

func azure functionapp publish <APP_NAME> --no-build

单元测试

可以通过标准测试框架,像测试其他 Python 代码那样测试以 Python 编写的函数。 对于大多数绑定,可以通过从 azure.functions 包创建相应类的实例来创建模拟输入对象。 由于 azure.functions 包并非立即可用,请务必通过 requirements.txt 文件安装该包,如前面的包管理部分中所述。

以 my_second_function 为例。 下面是 HTTP 触发的函数的模拟测试。

首先,为了创建 <project_root>/my_second_function/function.json 文件并将此函数定义为 HTTP 触发器,请使用以下代码:

{
  "scriptFile": "__init__.py",
  "entryPoint": "main",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

现在可以实现 my_second_function 和 shared_code.my_second_helper_function:

# <project_root>/my_second_function/__init__.py
import azure.functions as func
import logging

# Use absolute import to resolve shared_code modules
from shared_code import my_second_helper_function

# Define an HTTP trigger that accepts the ?value=<int> query parameter
# Double the value and return the result in HttpResponse
def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Executing my_second_function.')

    initial_value: int = int(req.params.get('value'))
    doubled_value: int = my_second_helper_function.double(initial_value)

    return func.HttpResponse(
      body=f"{initial_value} * 2 = {doubled_value}",
      status_code=200
    )
# <project_root>/shared_code/__init__.py
# Empty __init__.py file marks shared_code folder as a Python package
# <project_root>/shared_code/my_second_helper_function.py

def double(value: int) -> int:
  return value * 2

可以开始为 HTTP 触发器编写测试用例:

# <project_root>/tests/test_my_second_function.py
import unittest

import azure.functions as func
from my_second_function import main

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

        # Call the function.
        resp = main(req)

        # Check the output.
        self.assertEqual(
            resp.get_body(),
            b'21 * 2 = 42',
        )

在 .venv Python 虚拟环境中安装你偏好的 Python 测试框架,例如 pip install pytest。 然后运行 pytest tests 即可检查测试结果。

临时文件

tempfile.gettempdir() 方法返回一个临时文件夹,在 Linux 上为 /tmp。 应用程序可使用此目录存储函数在执行期间生成和使用的临时文件。

重要

不能保证写入临时目录的文件会在调用之间保留。 在横向扩展期间,临时文件不会在实例之间共享。

以下示例在临时目录 (/tmp) 中创建一个命名的临时文件:

import logging
import azure.functions as func
import tempfile
from os import listdir

#---
   tempFilePath = tempfile.gettempdir()
   fp = tempfile.NamedTemporaryFile()
   fp.write(b'Hello world!')
   filesDirListInTemp = listdir(tempFilePath)

建议在独立于项目文件夹的文件夹中维护测试。 此操作可防止对应用部署测试代码。

预安装的库

Python 上的 Azure Functions 运行时随附了几个库。

Python 标准库

Python 标准库包含每个 Python 发行版附带的内置 Python 模块列表。 其中的大多数库有助于你访问系统功能,如文件 I/O。 在 Windows 系统上,这些库随 Python 一起安装。 在 Unix 系统上,包集合提供了这些库。

若要查看这些库的完整详细信息,请使用以下链接:

辅助角色依赖项

Azure Functions 的 Python 辅助角色需要特定的一组库。 你也可以在函数中使用这些库,但它们并不属于 Python 标准库。 如果你的函数依赖于其中的任何一个库,则在 Azure Functions 外部运行时,这些函数可能无法在代码中使用。 可在 setup.py 文件的 install\_requires 节中找到依赖项的详细列表。

注意

如果函数应用的 requirements.txt 文件包含 azure-functions-worker 条目,请将其删除。 Azure Functions 平台会自动管理此辅助角色,我们会定期通过新功能和 Bug 修复更新此辅助角色。 在 requirements.txt 中手动安装旧版本的辅助角色可能会导致意外问题。

注意

如果你的包包含可能与辅助角色的依赖项冲突的某些库(例如 protobuf、TensorFlow 或 grpcio),请在应用设置中将 PYTHON_ISOLATE_WORKER_DEPENDENCIES 配置为 1,以防止应用程序引用该辅助角色的依赖项。 此功能为预览版。

Azure Functions 的 Python 库

每次 Python 辅助角色更新都包含一个新版本的 Azure Functions Python 库 (azure.functions)。 这种方法使持续更新 Python 函数应用变得更容易,因为每次更新都是向后兼容的。 可以在 PyPi 网站上的 azure-functions 信息中找到此库的版本列表。

运行时库版本由 Azure 修复,requirements.txt 不能替代此版本。 requirements.txt 中的 azure-functions 条目仅供 Lint 分析和客户认知。

使用以下代码在运行时中跟踪 Azure Functions Python 库的版本:

getattr(azure.functions, '__version__', '< 1.2.1')

运行时系统库

下表列出了 Docker 映像中为 Python 辅助角色预装的系统库:

Functions 运行时 Debian 版本 Python 版本
版本 2.x 拉伸 Python 3.7
3\.x 版 Buster Python 3.6
Python 3.7
Python 3.8
Python 3.9

Python 辅助角色扩展

在 Azure Functions 中运行的 Python 工作进程允许将第三方库集成到函数应用中。 这些扩展库充当中间件,可以在执行函数的生命周期内注入特定操作。

在与标准 Python 库模块类似的函数代码中导入扩展。 根据以下作用域执行扩展:

范围 说明
应用程序级别 将扩展导入到任何函数触发器后,该扩展将应用于应用中的每个函数执行。
函数级别 执行仅限于导入到其中的特定函数触发器。

查看扩展的信息,以详细了解扩展的运行范围。

扩展实现 Python 辅助角色扩展接口。 此操作允许 Python 工作进程在函数执行生命周期内调入扩展代码。

使用扩展

可以按照以下基本步骤在 Python 函数中使用 Python 辅助角色扩展库:

  1. 在项目的 requirements.txt 文件中添加扩展包。
  2. 将库安装到应用中。
  3. 添加应用程序设置 PYTHON_ENABLE_WORKER_EXTENSIONS
    • 若要在本地添加设置,请在 local.settings.json 文件Values 节中添加 "PYTHON_ENABLE_WORKER_EXTENSIONS": "1"
    • 若要在 Azure 中添加设置,请将 PYTHON_ENABLE_WORKER_EXTENSIONS=1 添加到应用设置
  4. 将扩展模块导入到函数触发器中。
  5. 配置扩展实例(如果需要)。 应在扩展文档中标注配置要求。

重要

Microsoft 不支持第三方 Python 辅助角色扩展库,也不为其提供担保。 请确保你在函数应用中使用的任何扩展可信。 对于使用恶意扩展或编写不当的扩展而带来的所有风险,均由你自己承担。

第三方应提供有关如何在函数应用中安装和使用其特定扩展的特定文档。 有关如何使用扩展的基本示例,请参阅使用扩展

下面是在函数应用中按范围使用扩展的示例:

# <project_root>/requirements.txt
application-level-extension==1.0.0
# <project_root>/Trigger/__init__.py

from application_level_extension import AppExtension
AppExtension.configure(key=value)

def main(req, context):
  # Use context.app_ext_attributes here

创建扩展

扩展是由已创建可集成到 Azure Functions 中的功能的第三方库开发人员创建的。 扩展开发人员设计、实现和发布 Python 包,其中包含专为在函数执行上下文中运行而设计的自定义逻辑。 这些扩展可以发布到 PyPI 注册表或 GitHub 存储库。

若要了解如何创建、打包、发布和使用 Python 辅助角色扩展包,请参阅为 Azure Functions 开发 Python 辅助角色扩展

应用程序级扩展

继承自 AppExtensionBase 的扩展在应用程序范围内运行。

AppExtensionBase 公开以下抽象类方法以供你实现:

方法 说明
init 在导入扩展后调用。
configure 根据需要从函数代码中调用以配置扩展。
post_function_load_app_level 在加载函数后立即调用。 函数名称和函数目录传递给扩展。 请记住,函数目录是只读的。 尝试写入到此目录中的本地文件都会失败。
pre_invocation_app_level 在触发函数前立即调用。 函数上下文和函数调用参数传递给扩展。 通常可以传递上下文对象中的其他属性,以供函数代码使用。
post_invocation_app_level 在函数执行完成后立即调用。 函数上下文、函数调用参数和调用返回对象将传递给扩展。 此实现是验证是否成功执行了生命周期挂钩的好方法。

函数级扩展

继承自特定函数触发器中的 FuncExtensionBase 运行的扩展。

FuncExtensionBase 公开以下抽象类方法以进行实现:

方法 说明
__init__ 在特定函数中初始化扩展实例时调用。 此方法是扩展的构造函数。 实现此抽象方法时,可能需要接受 filename 参数,并将其传递给父级的方法 super().__init__(filename) 以进行适当的扩展注册。
post_function_load 在加载函数后立即调用。 函数名称和函数目录传递给扩展。 请记住,函数目录是只读的。 尝试写入到此目录中的本地文件都会失败。
pre_invocation 在触发函数前立即调用。 函数上下文和函数调用参数传递给扩展。 通常可以传递上下文对象中的其他属性,以供函数代码使用。
post_invocation 在函数执行完成后立即调用。 函数上下文、函数调用参数和调用返回对象将传递给扩展。 此实现是验证是否成功执行了生命周期挂钩的好方法。

跨域资源共享

Azure Functions 支持跨域资源共享 (CORS)。 CORS 在门户中以及通过 Azure CLI 进行配置。 CORS 允许的来源列表应用于函数应用级别。 启用 CORS 后,响应包含 Access-Control-Allow-Origin 标头。 有关详细信息,请参阅 跨域资源共享

Python 函数应用完全支持 CORS。

异步

默认情况下,Python 的主机实例一次只能处理一个函数调用。 这是因为 Python 是单线程运行时。 对于处理大量 I/O 事件或受 I/O 约束的函数应用,可以通过异步运行函数来显著提高性能。 有关详细信息,请参阅在 Azure Functions 中提高 Python 应用的吞吐量性能

共享内存(预览版)

为了提高吞吐量,Azure Functions 允许进程外 Python 语言辅助角色与主机进程共享内存。 当函数应用遇到瓶颈时,可以通过添加名为 FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED 且值为 1 的应用程序设置来启用共享内存。 启用共享内存后,可以使用 DOCKER_SHM_SIZE 设置将共享内存设置为 268435456 之类的值,即相当于 256 MB。

例如,在使用 Azure Blob 存储绑定传输大于 1 MB 的有效负载时,可以启用共享内存以减少瓶颈。

此功能仅适用于在高级和专用(Azure 应用服务)计划中运行的函数应用。 要了解详细信息,请参阅共享内存

已知问题和常见问题解答

下面列出了常见问题的故障排除指南:

可以通过 GitHub 问题列表跟踪所有已知问题和功能请求。 如果遇到 GitHub 中未列出的问题,请打开“新问题”并提供问题的详细说明。

后续步骤

有关详细信息,请参阅以下资源:

遇到问题? 请告知我们。