Maison  >  Article  >  développement back-end  >  Une explication détaillée des gestionnaires de contexte Python et des blocs

Une explication détaillée des gestionnaires de contexte Python et des blocs

巴扎黑
巴扎黑original
2017-09-11 10:51:49948parcourir

Cet article présente principalement les informations pertinentes du gestionnaire de contexte Python et avec le bloc en détail. Il a une certaine valeur de référence. Les amis intéressés peuvent se référer au

Context Manager et avec le bloc, le contenu spécifique est. comme suit

L'objet gestionnaire de contexte existe pour gérer l'instruction with, tout comme l'itérateur existe pour gérer l'instruction for. Le but de l'instruction

with est de simplifier le modèle try/finally. Ce mode est utilisé pour garantir qu'une certaine opération est effectuée après la fin de l'exécution d'un morceau de code. Même si le code est terminé en raison d'une exception, d'une instruction return ou d'un appel sys.exit(), l'opération spécifiée sera. effectué. Le code de la clause finale est généralement utilisé pour libérer des ressources importantes ou restaurer un état temporairement modifié.

==Le protocole du gestionnaire de contexte contient deux méthodes, enter et exit==. Lorsque l'instruction with commence à s'exécuter, la méthode enter est appelée sur l'objet gestionnaire de contexte. Une fois l'exécution de l'instruction with terminée, la méthode exit est appelée sur l'objet gestionnaire de contexte, agissant ainsi comme la clausefinal.

==Le résultat de l'exécution de l'expression après with est l'objet gestionnaire de contexte. La liaison de la valeur à la variable cible (en tant que clause) est le résultat de l'appel de la méthode enter sur l'objet gestionnaire de contexte == . La clause as de l'instruction with est facultative. Pour la fonction open, une clause as doit être ajoutée pour obtenir une référence au fichier. Cependant, certains gestionnaires de contexte renverront None car il n'y a aucun objet utile à fournir à l'utilisateur.


with open('mirror.py') as fp:
  ...

Classe de contexte personnalisée :


class A:
  def __init__(self, name):
    self.name = name

  def __enter__(self):
    print('enter')
    return self.name

  def __exit__(self, exc_type, exc_val, exc_tb):
    print('gone')

with A('xiaozhe') as dt:
  print(dt)

module contextlib

Il existe également certaines classes et autres fonctions du module contextlib qui sont plus largement utilisées.

closing : Si l'objet fournit une méthode close() mais n'implémente pas le protocole enter/exit, vous pouvez utiliser cette fonction pour créer un gestionnaire de contexte.
suppress : construisez un gestionnaire de contexte qui ignore temporairement les exceptions spécifiées.
@contextmanager : ==Ce décorateur transforme une simple fonction génératrice en un gestionnaire de contexte==, il n'est donc pas nécessaire de créer une classe pour implémenter le protocole du gestionnaire.
ContextDecorator : il s'agit d'une classe de base utilisée pour définir des gestionnaires de contexte basés sur les classes. Ce gestionnaire de contexte peut également être utilisé pour décorer des fonctions, en exécutant l'intégralité de la fonction dans un contexte géré
ExitStack : Ce gestionnaire de contexte peut entrer dans plusieurs gestionnaires de contexte. À la fin du bloc with, ExitStack appelle les méthodes exit de chaque gestionnaire de contexte de la pile dans l'ordre dernier entré, premier sorti.

== Le plus utilisé est le décorateur @contextmanager, alors prêtez-y une attention particulière. Ce décorateur est également déroutant car il n'a rien à voir avec l'itération, mais utilise l'instruction rendement ==.

Utilisation de @contextmanager

Le décorateur @contextmanager peut réduire la quantité de code standard requis pour créer un gestionnaire de contexte au lieu d'écrire une classe complète définissant les méthodes d'entrée et de sortie. , seulement Vous devez implémenter un générateur avec une instruction rendement pour générer la valeur que vous souhaitez que la méthode enter renvoie.

Dans un générateur décoré avec @contextmanager, la fonction de l'instruction rendement est de diviser le corps de définition de la fonction en deux parties : ==yield Tout le code avant que l'instruction ne commence au début du bloc with (c'est-à-dire que l'interpréteur appelle la méthode enter ), le code qui suit l'instruction rendement s'exécute == à la fin du bloc with (c'est-à-dire lorsque la méthode exit est appelée).


import contextlib

@contextlib.contextmanager
def test(name):
  print('start')
  yield name
  print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')

Principe d'implémentation

le décorateur contextelib.contextmanager enveloppera la fonction dans une classe qui implémente les méthodes d'entrée et de sortie . Le nom de la classe est _GeneratorContextManager.

La méthode enter de cette classe a les fonctions suivantes :
1. Appelez la fonction générateur et enregistrez l'objet générateur (ici il est appelé gen).
2. Appelez next(gen) et exécutez à l'emplacement du mot-clé rendement.
3. Renvoie la valeur produite par next(gen) afin que la valeur produite puisse être liée à la variable cible dans l'instruction with/as.

Lorsque le bloc with se termine, la méthode de sortie fera les choses suivantes :

1 Vérifiez si l'exception a été transmise à exc_type ; si c'est le cas, appelez gen.throw(. exception), une exception est levée sur la ligne contenant le mot-clé rendement dans le corps de définition de la fonction génératrice.
2. Sinon, appelez next(gen) pour continuer à exécuter le code après l'instruction rendement dans le corps de définition de la fonction du générateur.

Gestion des exceptions

Afin d'indiquer à l'interpréteur que l'exception a été gérée, la méthode de sortie retournera True et l'interpréteur supprimera l'exception. Si la méthode exit ne renvoie pas explicitement de valeur, l'interpréteur obtient None et fait apparaître l'exception.

Lors de l'utilisation du décorateur @contextmanager, le comportement par défaut est inverse : la méthode de sortie fournie par le décorateur suppose que toutes les exceptions envoyées au générateur ont été gérées, et donc les exceptions doivent être supprimées. Si vous ne souhaitez pas que @contextmanager supprime les exceptions, vous devez explicitement renvoyer l'exception dans la fonction décorée.

Il y a un bug dans le code ci-dessus : si une exception est levée dans le bloc with, l'interpréteur Python l'attrapera puis la relancera dans l'expression rendement de la fonction de test. Cependant, il n’existe aucun code pour gérer l’erreur, donc la fonction de test est abandonnée.

使用 @contextmanager 装饰器时,要把 yield 语句放在 try/finally 语句中,因为我们永远不知道上下文管理器的用户会在 with 块中做什么。


import contextlib

@contextlib.contextmanager
def test(name):
  print('start')

  try:
    yield name
  except:
    raise ValueError('error')
  finally:
    print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn