Maison  >  Article  >  développement back-end  >  Comment utiliser l'instruction with de Python

Comment utiliser l'instruction with de Python

王林
王林avant
2023-05-25 17:22:061962parcourir

 Corps de l'instruction (with-body) : le bloc de code enveloppé dans l'instruction with appellera la méthode enter() du gestionnaire de contexte avant d'exécuter le corps de l'instruction, et la méthode exit() sera exécutée après l'exécution du corps de l'instruction.

  Syntaxe de base et principe de fonctionnement

  Le format de syntaxe de l'instruction with est le suivant :

 Listing 1. Format de syntaxe de l'instruction with

 with context_expression [comme cible(s)]:

 with -body

 Ici, contextexpression renvoie un objet gestionnaire de contexte, qui n'est pas affecté à la ou aux cibles dans la clause as. Si la clause as est spécifiée, la valeur de retour de la méthode _enter() du gestionnaire de contexte sera attribuée à la cible. (s). la ou les cibles peuvent être une variable unique ou un tuple entouré de "()" (il ne peut pas s'agir d'une liste de variables séparées uniquement par ",", "()" doit être ajouté).

 Python a amélioré certains objets intégrés et ajouté la prise en charge des gestionnaires de contexte, qui peuvent être utilisés avec des instructions, telles que la fermeture automatique de fichiers, l'acquisition et la libération automatiques de verrous de thread, etc. Supposons que vous souhaitiez utiliser un fichier, vous pouvez utiliser l'instruction with pour obtenir le code suivant :

 Listing 2. Utilisez l'instruction with pour utiliser l'objet fichier

 with open(r'somefileName') as somefile:

 ligne for dans un fichier :

 ligne d'impression

 # ...plus de code

 L'instruction with est utilisée ici Qu'une exception se produise ou non pendant le traitement du fichier, il est garanti que le descripteur de fichier ouvert a été fermé après le. L'instruction with est exécutée. Si vous utilisez le paradigme traditionnel try/finally, vous devez utiliser un code similaire au suivant :

 Listing 3. Méthode Try/finally pour faire fonctionner les objets fichier

 somefile = open(r'somefileName')

 try:

 for line in somefile:

 print line

 # ...plus de code

 finally:

 somefile.close()

 En comparaison, l'utilisation de l'instruction with peut réduire la quantité de codage. Des modules threading, décimal, etc. ont également été ajoutés pour prendre en charge le protocole de gestion de contexte.

 PEP 0343 décrit l'implémentation de l'instruction with. Le processus d'exécution de l'instruction with est similaire au bloc de code suivant :

 Listing 4. Processus d'exécution de l'instruction With

  context_manager = context_expression

  exit = type(context_manager).__exit__

 value = type(context_manager). __enter__(context_manager)

  exc = True # True signifie une exécution normale, même s'il y a une exception, elle sera ignorée ; False signifie relancer l'exception, et l'exception doit être gérée

 try:

 try :

 target = value # Si la clause as est utilisée

with-body # Exécuter with-body

  sauf : # Une exception se produit pendant l'exécution

 exc = False

  # Si __exit__ renvoie True, l'exception est ignorée ; s'il renvoie False, l'exception est renvoyée

  # Les exceptions sont gérées par le code externe

 if not exit(context_manager, *sys.exc_info()):

 raise

 finally:

  #Quitter normalement, ou via l'instruction break/continue/return dans le corps de l'instruction Exit

  # Ou ignorez l'exception et exit

 if exc:

 exit(context_manager, None, None, None)

  # Renvoie Aucun par défaut, Aucun n'est considéré comme faux dans un contexte booléen

 Exécutez context_expression pour générer la gestion du contexte context_manager.

  Appelez la méthode enter() du gestionnaire de contexte ; si la clause as est utilisée, attribuez la valeur de retour de la méthode enter() à la ou aux cibles dans la clause as.

  Execution Statement body with-body

  Qu'une exception se produise ou non pendant l'exécution, la méthode exit() du gestionnaire de contexte est exécutée. La méthode exit() est chargée d'effectuer un travail de « nettoyage », tel que la libération. ressources, etc Si aucune exception ne se produit pendant l'exécution ou si l'instruction break/continue/return est exécutée dans le corps de l'instruction, appelez exit(None, None, None) avec None comme paramètre si une exception se produit pendant l'exécution, utilisez sys.excinfo L'exception ; l'information est l'appel de paramètre _exit(exc_type, exc_value, exc_traceback).

 Lorsqu'une exception se produit, si exit(type, value, traceback) renvoie False, l'exception sera renvoyée, permettant à une logique d'instruction autre que with de gérer l'exception. l'exception sera ignorée. Ensuite, gérez l'exception.

 Gestionnaire de contexte personnalisé

 Les développeurs peuvent personnaliser les classes qui prennent en charge le protocole de gestion de contexte. Le gestionnaire de contexte personnalisé doit implémenter les deux méthodes enter() et exit() requises pour le protocole de gestion de contexte :

 contextmanager._enter() : saisissez le contexte d'exécution du gestionnaire de contexte et appelez-le avant que le corps de l'instruction ne soit exécuté. L'instruction with attribue la valeur de retour de la méthode à la cible dans la clause as, si celle-ci est spécifiée.

 contextmanager._exit(exc_type, exc_value, exc_traceback) : Quitte le contexte d'exécution lié au gestionnaire de contexte et renvoie une valeur booléenne indiquant s'il faut gérer l'exception qui s'est produite. Les paramètres indiquent l'exception qui a provoqué l'opération de sortie. Si aucune exception ne se produit lors de la sortie, les trois paramètres sont Aucun. Si une exception se produit, revenez.

True signifie ne pas gérer l'exception, sinon l'exception sera à nouveau levée après la sortie de la méthode pour être gérée par la logique du code en dehors de l'instruction with. Si une exception est déclenchée dans cette méthode, elle remplacera l'exception déclenchée par l'instruction dans le corps de l'instruction. Lors du traitement d'une exception, ne relancez pas explicitement l'exception, c'est-à-dire que vous ne pouvez pas relancer l'exception transmise via les paramètres. Il vous suffit de définir la valeur de retour sur False. Le code de gestion de contexte détecte ensuite si exit() n'a pas réussi à gérer l'exception.

Ce qui suit est un exemple simple pour montrer comment créer un gestionnaire de contexte personnalisé. Notez que le gestionnaire de contexte doit fournir des définitions pour les méthodes enter() et exit() ; l'absence de l'une ou l'autre entraînera une erreur AttributeError ; l'instruction with vérifie d'abord si la méthode exit() est fournie, puis vérifie si la méthode enter(). est défini.

Supposons qu'il existe une ressource DummyResource. Cette ressource doit être allouée avant l'accès et libérée après utilisation. L'opération d'allocation peut être placée dans la méthode enter() et l'opération de libération peut être placée dans exit. () dans la méthode. Par souci de simplicité, seules les instructions print sont utilisées pour indiquer l'opération en cours, et il n'y a pas d'allocation ni de libération réelle de ressources.

 Listing 5. Objets personnalisés qui prennent en charge l'instruction with

 class DummyResource:

def __init__(self, tag):

Self.tag = tag

print 'Ressource [%s]' % tag

def __enter__(self):#🎜 🎜#

 print '[Entrez %s] : Allouer la ressource.' % self.tag

Return self # Différents objets peuvent être renvoyés

def __exit__(self , exc_type, exc_value, exc_tb):

print '[Sortie %s] : Ressource gratuite.' % self.tag

si exc_tb est Aucun :

# 🎜🎜# print '[Sortie %s] : Sortie sans exception.' % self.tag

else:

print '[Sortie %s] : Sortie avec exception levée .' % self.tag

Return False # Peut être omis, la valeur par défaut None est également considérée comme False

Enter() dans DummyResource renvoie une référence à elle-même, cette référence peut être attribué à la variable cible dans la clause as ; le type de la valeur de retour peut être défini sur un type différent en fonction des besoins réels et ne doit pas nécessairement être l'objet du gestionnaire de contexte lui-même.

La variable exctb est détectée dans la méthode exit(). Si ce n'est pas None, cela signifie qu'une exception s'est produite. Renvoyer False signifie que l'exception doit être gérée par une logique de code externe ; que si aucune exception ne se produit, la valeur de retour manquante de la province est None, ce qui est également considéré comme False dans un environnement booléen. Cependant, comme aucune exception ne se produit, les trois paramètres de _exit() sont None. Le code de gestion du contexte peut. détecter cette situation et la gérer normalement.

Ce qui suit permet d'accéder à DummyResource dans l'instruction with :

Listing 6. Utiliser un objet personnalisé qui prend en charge l'instruction with

#🎜🎜 ##🎜 🎜# With DummyResource('Normal'): print '[with-body] Exécuter sans exceptions.'

with DummyResource('With-Exception') :#🎜 Échec de la fin du corps de l'instruction !'

Le résultat de l'exécution de la première instruction with est le suivant :

 

Listing 7. Exécution de l'instruction With 1 result

#🎜🎜 #

 Ressource [Normal]

 [Entrez Normal] : allouer une ressource.

 [with-body] Exécutez sans exceptions.

[Quitter Normal] : Ressource gratuite.

 [Quitter Normal] : Quitter sans exception.

 Comme vous pouvez le constater, lors d'une exécution normale, le corps de l'instruction with-body sera exécuté en premier. Exécutez ensuite la méthode exit() pour libérer les ressources.

Le résultat de l'exécution de la deuxième instruction with est le suivant :

Liste 8. Résultat de l'exécution de l'instruction With 2

#🎜 🎜# Ressource [With-Exception]

 [Entrez avec-exception] : Allouer la ressource.

 [with-body] Exécuter avec exception.

#🎜🎜 # [Quitter avec exception] : Ressource gratuite.

 [Quitter avec exception] : Quitter avec exception levée.

 Traceback (dernier appel le plus récent) :#🎜🎜 ## 🎜🎜# Fichier "G:/demo", ligne 20, dans raise Exception

 Exception

 Vous pouvez voir que lorsqu'une exception se produit dans with-body, avec -body ne le fait pas Une fois l'exécution terminée, la libération des ressources sera garantie et les exceptions générées en même temps seront interceptées et gérées par la logique du code en dehors de l'instruction with.

Vous pouvez personnaliser le gestionnaire de contexte pour gérer les ressources du système logiciel, telles que les connexions à la base de données, le contrôle d'accès aux ressources partagées, etc. La documentation en ligne Python Writing Context Managers fournit un exemple simple de gestionnaire de contexte pour gérer les connexions à une base de données.

Module Contextlib

 Le module contextlib fournit 3 objets : décorateur contextmanager, fonction imbriquée et contexte gestionnaire de fermeture. À l'aide de ces objets, vous pouvez encapsuler des fonctions ou des objets générateurs existants et ajouter la prise en charge du protocole de gestion de contexte, évitant ainsi d'avoir à écrire un gestionnaire de contexte spécifiquement pour prendre en charge l'instruction with.

 Le contextmanager du décorateur

 Le contextmanager est utilisé pour décorer la fonction génératrice. Une fois la fonction génératrice décorée, un gestionnaire de contexte est renvoyé et ses méthodes enter() et exit() sont fournies par le contextmanager au lieu de l'itérateur précédent. . La fonction générateur décoré ne peut produire qu'une seule valeur, sinon elle provoquera une exception RuntimeError ; la valeur générée sera affectée à la cible dans la clause as, si la clause as est utilisée. Regardons un exemple simple.装. Listing 9. Le décorateur ContextManager utilise des exemples

de contextLib importingManager

@contextManager

def demo ():

)

Print 'Code Bef Ore Yield-Statement Executes in __ENTER__ '

 yield' ** * démo de contextmanager ***'

 imprimer 'Le code après l'exécution de la déclaration de rendement dans __exit__'

 imprimer '[Ressources gratuites]'

 avec demo() comme valeur :

 imprimer 'Valeur assignée : %s' % valeur Le résultat est le suivant :

  Le code après l'exécution de l'instruction rendement dans __exit__

  [Ressources gratuites]

  On peut voir que l'instruction avant rendement dans la fonction génératrice est exécutée dans la méthode enter(), et l'instruction après rendement est exécutée dans exit( ) est exécuté dans et la valeur générée par rendement est affectée à la variable de valeur dans la clause as.

 Il est à noter que contextmanager omet uniquement l'écriture de enter() / exit(), mais n'est pas responsable de réaliser "l'acquisition" et le "nettoyage" des ressources, l'opération "d'acquisition" doit être définie avant le rendement ; et "cleaning" "L'opération doit être définie après l'instruction rendement, afin que l'instruction with exécute ces instructions pour obtenir/libérer des ressources lors de l'exécution de la méthode enter() / exit(), c'est-à-dire la logique nécessaire le contrôle doit être implémenté dans la fonction du générateur, y compris lorsqu'une erreur se produit lors de l'accès aux ressources. Lancez des exceptions appropriées.

 

Fonction nested

  Nested peut organiser plusieurs gestionnaires de contexte ensemble pour éviter d'utiliser des instructions nested with.

 

Listing 11. syntaxe imbriquée

 avec imbriqué (A(), B(), C()) comme (X, Y, Z) :

  # avec code avec corps ici

  Similaire à :

Listing 12. processus d'exécution imbriqué

 avec A() as Après qu'une exception se produit, si la méthode exit() d'un gestionnaire de contexte renvoie False pour la gestion des exceptions, le gestionnaire de contexte externe ne détectera pas l'exception.

 Fermeture du gestionnaire de contexte

 La mise en œuvre de la fermeture est la suivante :

 

Listing 13. Implémentation de la fermeture de la gestion du contexte

 fermeture de la classe (objet):

 # help doc here

 def __init__ (moi, chose ):

 self.thing = thing

  def __enter__(self):

  return self.thing

  def __exit__(self, *exc_info):

  self.thing.close()

  Le gestionnaire de contexte terminera l'objet est affecté à la variable cible de la clause as, et il est assuré que l'objet ouvert sera fermé après l'exécution de with-body. L'objet encapsulé par le gestionnaire de contexte de fermeture doit fournir la définition de la méthode close(), sinon une AttributeError sera signalée lors de l'exécution.

 

Listing 14. Personnaliser les objets qui prennent en charge la fermeture

 class ClosingDemo(object):

 def __init__(self):

 self.acquire()

 def acquire(self):

 print 'Ac exiger des ressources. '

  def free (self):

print 'Nettoyer toutes les ressources acquises.' Utilisation des ressources'

 Le résultat est le suivant :

 

Listing 15. Le résultat de sortie de l'objet de fermeture personnalisé

 Acquérir ressources.

 Utilisation des ressources

 Nettoyez toutes les ressources acquises.

 closing convient pour fournir close() Les objets implémentés, tels que les connexions réseau, les connexions à la base de données, etc., peuvent également effectuer le travail de « nettoyage » des ressources requis via le interface close() lors de la personnalisation de la classe.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer