Guía de Azure Functions para desarrolladores de PythonAzure Functions Python developer guide

Este artículo es una introducción al desarrollo de Azure Functions mediante Python.This article is an introduction to developing Azure Functions using Python. En lo que va a leer a continuación se supone que ya ha leído la guía para desarrolladores de Azure Functions.The content below assumes that you've already read the Azure Functions developers guide.

Nota

Python for Azure Functions is currently in preview. To receive important updates, subscribe to the Azure App Service announcements repository on GitHub.

Modelo de programaciónProgramming model

Una función de Azure Function debe ser un método sin estado de un script de Python que procese entradas y produzca salidas.An Azure Function should be a stateless method in your Python script that processes input and produces output. De forma predeterminada, el runtime espera que el modelo se implemente como un método global denominado main() en el archivo __init__.py.By default, the runtime expects the method to be implemented as a global method called main() in the __init__.py file.

Puede cambiar la configuración predeterminada si especifica las propiedades scriptFile y entryPoint en el archivo function.json.You can change the default configuration by specifying the scriptFile and entryPoint properties in the function.json file. Por ejemplo, el archivo function.json siguiente indica al runtime que use el método customentry() del archivo main.py, como punto de entrada para la instancia de Azure Functions.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",
  ...
}

Los datos de los desencadenadores y enlaces se enlazan a la función a través de los atributos del método con la propiedad name definida en el archivo 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. Por ejemplo, en el archivo function.json siguiente se describe una función simple desencadenada por una solicitud HTTP denominada 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"
    }
  ]
}

El archivo __init__.py contiene el código de función siguiente:The __init__.py file contains the following function code:

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

Opcionalmente, para aprovechar las características de IntelliSense y Autocompletar proporcionadas por su editor de código, también puede declarar los tipos de atributo y el tipo de valor devuelto en la función mediante anotaciones de tipo 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}!'

Utilice las anotaciones de Python incluidas en el paquete azure.functions.* para enlazar las entradas y las salidas a los métodos.Use the Python annotations included in the azure.functions.* package to bind input and outputs to your methods.

Estructura de carpetasFolder structure

La estructura de carpetas para un proyecto de Python de Azure Functions tiene la siguiente apariencia: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

Hay un archivo host.json compartido que se puede usar para configurar la aplicación de función.There's a shared host.json file that can be used to configure the function app. Cada función tiene su propio archivo de código y archivo de configuración de enlace (function.json).Each function has its own code file and binding configuration file (function.json).

El código compartido debe mantenerse en una carpeta independiente.Shared code should be kept in a separate folder. Para hacer referencia a los módulos en la carpeta SharedCode, puede usar la sintaxis siguiente:To reference modules in the SharedCode folder, you can use the following syntax:

from __app__.SharedCode import myFirstHelperFunction

Al implementar un proyecto de Functions en la aplicación de funciones en Azure, todo el contenido de la carpeta FunctionApp debe incluirse en el paquete, pero no en la carpeta.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.

Desencadenadores y entradasTriggers and Inputs

Las entradas se dividen en dos categorías dentro de Azure Functions: una entrada del desencadenador y otra adicional.Inputs are divided into two categories in Azure Functions: trigger input and additional input. Aunque son diferentes en el archivo function.json, se usan igual en el código de Python.Although they are different in the function.json file, usage is identical in Python code. Las cadenas de conexión o los secretos de los orígenes de entrada y el desencadenador se asignan a valores en el archivo local.settings.json al ejecutarse localmente y a la configuración de la aplicación al ejecutarse en 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.

Por ejemplo, el siguiente código muestra la diferencia entre las dos: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()}')

Cuando se invoca la función, la solicitud HTTP se pasa a la función como req.When the function is invoked, the HTTP request is passed to the function as req. Se recuperará una entrada de Azure Blob Storage según el identificador de la dirección URL de la ruta y estará disponible como obj en el cuerpo de la función.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. Aquí, la cuenta de almacenamiento especificada es la cadena de conexión encontrada en AzureWebJobsStorage, que es la misma cuenta de almacenamiento que usa la aplicación de funciones.Here the storage account specified is the connection string found in AzureWebJobsStorage which is the same storage account used by the function app.

SalidasOutputs

Las salidas se pueden expresar como valores devueltos y como parámetros de salida.Output can be expressed both in return value and output parameters. Si hay una única salida, se recomienda usar el valor devuelto.If there's only one output, we recommend using the return value. Para varias salidas, deberá utilizar parámetros de salida.For multiple outputs, you'll have to use output parameters.

Para usar el valor devuelto de una función como valor de un enlace de salida, la propiedad name del enlace debe establecerse como $return en function.json.To 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.

Si desea generar varias salidas, utilice el método set() que la interfaz azure.functions.Out ofrece para asignar un valor al enlace.To produce multiple outputs, use the set() method provided by the azure.functions.Out interface to assign a value to the binding. Por ejemplo, la siguiente función puede insertar un mensaje en una cola y también devolver una respuesta 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

RegistroLogging

El acceso al registrador del entorno de ejecución de Azure Functions está disponible a través de un controlador logging raíz en la aplicación de función.Access to the Azure Functions runtime logger is available via a root logging handler in your function app. Este registrador está asociado a Application Insights y permite marcar las advertencias y los errores detectados durante la ejecución de la función.This logger is tied to Application Insights and allows you to flag warnings and errors encountered during the function execution.

En el ejemplo siguiente se registra un mensaje de información cuando la función se invoca con un desencadenador 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.')

Hay métodos de registro adicionales disponibles que permiten escribir en la consola en otros niveles de seguimiento:Additional logging methods are available that let you write to the console at different trace levels:

MétodoMethod DESCRIPCIÓNDescription
logging.critical(message)logging.critical(message) Escribe un mensaje con el nivel CRÍTICO en el registrador de raíz.Writes a message with level CRITICAL on the root logger.
logging.error(message)logging.error(message) Escribe un mensaje con el nivel ERROR en el registrador de raíz.Writes a message with level ERROR on the root logger.
logging.warning(message)logging.warning(message) Escribe un mensaje con el nivel ADVERTENCIA en el registrador de raíz.Writes a message with level WARNING on the root logger.
logging.info(message)logging.info(message) Escribe un mensaje con el nivel INFO en el registrador de raíz.Writes a message with level INFO on the root logger.
logging.debug(message)logging.debug(message) Escribe un mensaje con el nivel DEBUG en el registrador de raíz.Writes a message with level DEBUG on the root logger.

AsyncAsync

Le recomendamos que escriba su instancia de Azure Functions como corrutina asincrónica mediante la instrucción 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()

Si la función main() es sincrónica (no tiene el calificador async), se ejecuta automáticamente en un grupo de subprocesos 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

Para obtener el contexto de invocación de una función durante la ejecución, incluya el argumento context en su firma.To get the invocation context of a function during execution, include the context argument in its signature.

Por ejemplo:For example:

import azure.functions


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

La clase Context tiene los métodos siguientes:The Context class has the following methods:

function_directory
El directorio en que se ejecuta la función.The directory in which the function is running.

function_name
El nombre de la función.Name of the function.

invocation_id
El identificador de la invocación de la función actual.ID of the current function invocation.

Variables globalesGlobal variables

No se garantiza la conservación del estado de la aplicación para las ejecuciones futuras.It is not guaranteed that the state of your app will be preserved for future executions. Sin embargo, Azure Functions Runtime suele reutilizar el mismo proceso para varias ejecuciones de la misma aplicación.However, the Azure Functions runtime often reuses the same process for multiple executions of the same app. Para almacenar en caché los resultados de un cálculo costoso, debe declararse como variable global.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

La versión de Python y la administración de paquetes.Python version and package management

Actualmente, Azure Functions admite solo Python 3.6.x (distribución oficial de CPython).Currently, Azure Functions only supports Python 3.6.x (official CPython distribution).

Al desarrollar localmente con Azure Functions Core Tools o Visual Studio Code, agregue los nombres y las versiones de los paquetes necesarios al archivo requirements.txt e instálelos mediante 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.

Por ejemplo, se puede usar el comando de archivo y pip siguiente para instalar el paquete requests desde PyPI.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

Publicación en AzurePublishing to Azure

Cuando esté preparado para la publicación, asegúrese de que todas sus dependencias se muestran en el archivo requirements.txt, que se encuentra en la raíz del directorio del proyecto.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. Si usa un paquete que requiere un compilador y no admite la instalación de ruedas compatibles con manylinux desde PyPI, se producirá el error siguiente en la publicación en 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

Para compilar y configurar los archivos binarios necesarios automáticamente, instale Docker en el equipo local y ejecute el siguiente comando para publicar con 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). Reemplace <app name> por el nombre de la aplicación de función de Azure.Remember to replace <app name> with the name of your function app in Azure.

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

Interiormente, Core Tools usará Docker para ejecutar la imagen mcr.microsoft.com/azure-functions/python como un contenedor en la máquina local.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. Con este entorno, se compilarán e instalarán los módulos necesarios desde la distribución de origen, antes de empaquetarlos para la implementación final en 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.

Para crear sus dependencias y publicarlas mediante un sistema de entrega continua (CD), use Azure DevOps Pipelines.To build your dependencies and publish using a continuous delivery (CD) system, use Azure DevOps Pipelines.

Pruebas unitariasUnit Testing

Las funciones escritas en Python se pueden probar como otro código de Python mediante marcos de pruebas.Functions written in Python can be tested like other Python code using standard testing frameworks. Para la mayoría de los enlaces, es posible crear un objeto de entrada ficticio creando una instancia de una clase adecuada a partir del paquete 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. Puesto que el paquete azure.functions no está disponible inmediatamente, asegúrese de instalarlo a través del archivo requirements.txt, tal como se describe en la sección anterior La versión de Python y la administración de paquetes.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.

Por ejemplo, a continuación se muestra una prueba ficticia de una función desencadenada por 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',
        )

Este es otro ejemplo, con una función desencadenada por la cola: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',
        )

Problemas conocidos y preguntas más frecuentesKnown issues and FAQ

Todos los problemas conocidos y las solicitudes de características se siguen mediante la lista deproblemas de GitHub.All known issues and feature requests are tracked using GitHub issues list. Si le surge algún problema y no lo encuentra en GitHub, abra un nuevo problema e incluya una descripción detallada del mismo.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.

Pasos siguientesNext steps

Para obtener más información, consulte los siguientes recursos:For more information, see the following resources: