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 :
- 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).
- Dans la fonction d'origine, transmettez la fonction de rappel en tant que paramètre à la fonction qui nécessite un rappel.
- 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
Dans le code ci-dessus, nous définissons d'abord une fonction de rappel callback
, puis async_function
passons 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.partial
Il 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.
partial
La fonction est utilisée comme suit :
functools.partial(func, *args, **kwargs)
Parmi eux, func
se trouvent les fonctions à appliquer partiellement et *args 和 **kwargs
les paramètres à fixer.
Plus précisément, partial
la 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 partial
la 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 partial
la 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, partial
trois nouvelles fonctions sont définies à l'aide de la fonction add3、add4、add5
pour 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
, socket
qui est transmise en paramètre au constructeur de classe une fois la connexion terminée TestClient
pour traiter les messages reçus et traiter les données renvoyées par le serveur via des rappels.
résultat de l'opération
Ce qui précède est python functools.partial
une introduction de base à la configuration des fonctions de rappel pour gérer les tâches asynchrones. J'espère que cela vous sera utile !