Python - Fonction de rappel de paramétrage functools.partial pour gérer les tâches asynchrones

Introduction

En Python, une fonction de rappel fait référence au processus d'appel d'une autre fonction une fois l'exécution d'une fonction terminée. Normalement, la fonction de rappel est passée en paramètre à la fonction d'origine. Une fois que la fonction d'origine a exécuté sa propre logique, elle appellera automatiquement la fonction de rappel et lui transmettra le résultat en tant que paramètre.

2. Utilisation de base des fonctions de rappel

Voici les étapes de base pour configurer une fonction de rappel en Python :

  1. Définissez la fonction de rappel et déterminez la liste des paramètres de la fonction de rappel et la valeur de retour (le cas échéant).
  2. Dans la fonction d'origine, transmettez la fonction de rappel en tant que paramètre à la fonction qui nécessite un rappel.
  3. Appelez la fonction de rappel à l'emplacement approprié dans la fonction d'origine, en lui transmettant les paramètres qui doivent être transmis.

Par exemple, en supposant que nous devions configurer une fonction de rappel pour gérer les résultats d'une opération asynchrone, nous pouvons la configurer comme suit :

# 定义回调函数
def callback(result):
    print('Callback function is called with result: ', result)

# 异步函数,需要传入回调函数
def async_function(param1, param2, callback):
    # 进行异步操作
    result = param1 + param2
    # 异步操作完成后调用回调函数
    callback(result)

# 调用异步函数,并传入回调函数
async_function(1, 2, callback)

Résultats d'exécution
Insérer la description de l'image ici
Dans le code ci-dessus, nous définissons d'abord une fonction de rappel callback, puis async_functionpassons la fonction en tant que paramètre dans la fonction asynchrone et appelons la fonction de rappel une fois l'opération asynchrone terminée pour lui transmettre le résultat de l'opération.

Habituellement, nous définissons la fonction de rappel comme un objet appelable, c'est-à-dire un __call__objet de classe qui implémente la méthode. En utilisant cette méthode, la fonction de rappel peut être définie de manière plus flexible et certaines informations d'état ou de contexte peuvent être stockées dans l'objet et utilisées dans la fonction de rappel.

3. Avancé - Utilisez functools.partial pour transférer des fonctions

1. Introduction de base à functools.partial

functools.partialIl s'agit d'une fonction de la bibliothèque standard Python, utilisée pour appliquer partiellement une fonction (application partielle), c'est-à-dire pour fixer une partie des paramètres de la fonction et renvoyer une nouvelle fonction.
partialLa fonction est utilisée comme suit :

functools.partial(func, *args, **kwargs)

Parmi eux, funcse trouvent les fonctions à appliquer partiellement et *args 和 **kwargsles paramètres à fixer.

Plus précisément, partialla fonction renverra un nouvel objet fonction. Ce nouvel objet fonction est similaire à l'objet fonction d'origine, mais certains paramètres sont fixes, ce qui équivaut à ce que la fonction d'origine devienne une fonction avec des paramètres par défaut. Nous pouvons utiliser ce nouvel objet fonction pour appeler la fonction d'origine sans transmettre les paramètres fixes.

Voici un exemple de code simple montrant comment utiliser partialla fonction :

import functools

# 定义一个简单的加法函数
def add(a, b):
    return a + b

# 固定 add 函数的第一个参数
add2 = functools.partial(add, 2)

# 调用 add2 函数
print(add2(3))  # 输出:5

Dans l'exemple de code ci-dessus, nous définissons une simple fonction d'addition add, puis utilisons partialla fonction pour fixer le premier paramètre de la fonction add à 2 afin d'obtenir un nouvel objet fonction add2. Ensuite, nous utilisons la fonction add2 pour calculer le résultat de 2+3 et afficher le résultat sur la console.

L’avantage de l’utilisation de fonctions partielles est qu’elle facilite la définition de nouvelles fonctions et évite la duplication de code. Par exemple, si nous voulons définir une fonction qui ajoute 3, 4 et 5, nous pouvons utiliser partial pour l'implémenter sans avoir à écrire plusieurs fonctions similaires.

add3 = functools.partial(add, 3)
add4 = functools.partial(add, 4)
add5 = functools.partial(add, 5)

print(add3(2))  # 输出:5
print(add4(2))  # 输出:6
print(add5(2))  # 输出:7

Dans l'exemple de code ci-dessus, partialtrois nouvelles fonctions sont définies à l'aide de la fonction add3、add4、add5pour fixer les ajouts à 3, 4 et 5 respectivement, puis ces nouvelles fonctions sont utilisées pour calculer les résultats de 2+3, 2+4 et 2+. 5. et affichez les résultats sur la console.

2. Exemple de code pour une utilisation avancée de functools.partial

Examinons ensuite un exemple d'appel d'une fonction de rappel après une connexion socket réussie :

1. Démarrez un service de serveur socket

import json
import os
import socket
import threading
import time
import sys
import traceback

HOST = '127.0.0.1'  # 服务器IP地址
PORT = 8000  # 服务器端口号
BACKLOG = 5  # 服务器监听队列大小,即最多同时接收多少个客户端连接
RECONNECT_INTERVAL = 5  # 重连间隔,单位:秒


def start_server():
    print(os.getpid())
    while True:
        try:
            # 创建一个 TCP/IP socket 对象
            server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            # 绑定服务器 IP 地址和端口号
            server_socket.bind((HOST, PORT))

            # 开始监听客户端连接请求
            server_socket.listen(BACKLOG)
            print('服务器启动,监听端口:%s' % PORT)

            while True:
                # 等待客户端连接
                print('等待客户端连接...')
                try:
                    client_socket, client_address = server_socket.accept()
                    threading.Thread(target=send_msg, args=(client_socket, client_address)).start()
                    # send_msg(client_socket, client_address)
                    print(f"Process {
      
      threading.current_thread()}: {
      
      threading.active_count()} threads")
                    print(f"Total threads: {
      
      threading.active_count()}")

                    print('新客户端连接,地址:%s' % str(client_address))

                    # 读取客户端发送的数据
                    data = client_socket.recv(1024)
                    print('Received data:', data.decode())

                    # 向客户端发送数据
                    message = 'Welcome to my server!'
                    client_socket.sendall(message.encode())

                except Exception as e:
                    print('客户端连接异常,错误信息:%s' % e)

                finally:
                    # 关闭客户端连接
                    client_socket.close()
                    print('客户端连接已关闭')

        except Exception as e:
            print('服务器异常,错误信息:%s' % e)
            traceback.print_exc()

            # 关闭服务端 socket
            server_socket.close()
            print('{}s后尝试重连服务器...'.format(RECONNECT_INTERVAL))
            time.sleep(RECONNECT_INTERVAL)


def send_msg(client, addr):
    try:
        while 1:
            time.sleep(1)
            jsonTemplate = {
    
    
                "Command": "FORWARD_ELEV_INFO",
                "DeviceId": "C0002T",
                "ElevId": 1,
            }
            msg2Elev = json.dumps(jsonTemplate).encode() + "\n".encode()
            client.sendto(msg2Elev, addr)
            print('send msg to client:{}:{}'.format(addr, msg2Elev))
    except Exception as e:
        print('send_msg:{}'.format(e))


if __name__ == '__main__':
    # 启动服务器
    start_server()

2. Ouvrez une connexion client et appelez la fonction de rappel une fois la connexion établie.

import functools
import json
import socket
import threading
import time
import traceback


class TestClient(threading.Thread):

    def __init__(self, connectHost, connectPort, callbackFunc):
        threading.Thread.__init__(self, name="TestClient")
        self.host = connectHost
        self.port = connectPort
        self.callbackFunc = callbackFunc
        self.sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def run(self):

        self.connect()
        while True:
            try:
                # 从socket中读取数据
                # data = self.sck.recv(1024)
                # print(data)
                data = self.recv_msg(self.sck)
                if data is None:
                    time.sleep(1)
                    continue
                self.callbackFunc(data)
            except OSError:
                # An operation was attempted on something that is not a socket
                traceback.print_exc()
                time.sleep(5)
                # FIXME: if socket is broken, reconnect with the same sck does not work, so create an new one.
                self.sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.connect()

            except Exception as e:
                # TODO: if disconnected, connect it
                traceback.print_exc()
                time.sleep(5)
                self.connect()

    def recv_msg(self, sock):
        try:
            data = sock.recv(1024)
            print('recv data:{}'.format(data))
            return data
        except Exception as e:
            print('recv_msg:{}'.format(e))
            sock.close()
            time.sleep(0.5)

    def connect(self):

        while True:
            try:
                self.sck.connect((self.host, self.port))
                print("connected to Service {}:{}".format(self.host, self.port))
                break
            except ConnectionRefusedError:
                print("service refused or not started? Reconnecting to Service in 5s")
                time.sleep(5)

            except Exception as e:
                print("connect error type->{}".format(type(e)))
                traceback.print_exc()
                # FIXME: if other exception, not sure to restart action will work.
                time.sleep(5)


def callbackFunc(a, res):
    print(a)
    print('callback msg -- >', res)


if __name__ == '__main__':
    connectHost = '127.0.0.1'
    connectPort = 8000
    callbackFunc = callbackFunc

    elevClient = TestClient(connectHost, connectPort, functools.partial(callbackFunc, 'hello callback'))
    elevClient.start()

Le programme ci-dessus définit une fonction de rappel callbackFunc, socketqui est transmise en paramètre au constructeur de classe une fois la connexion terminée TestClientpour traiter les messages reçus et traiter les données renvoyées par le serveur via des rappels.

résultat de l'opération
Insérer la description de l'image ici

Ce qui précède est python functools.partialune introduction de base à la configuration des fonctions de rappel pour gérer les tâches asynchrones. J'espère que cela vous sera utile !

Je suppose que tu aimes

Origine blog.csdn.net/qq_43030934/article/details/132580785
conseillé
Classement