Expliquer en détail avec et gestionnaire de contexte en Python

with Ce mot-clé est familier à tous ceux qui apprennent Python.

Lors de la manipulation d'objets texte, presque tout le monde nous laisse les utiliser, with openc'est un exemple de gestion de contexte. Vous devez être assez familier avec ça, je ne dirai plus de bêtises.

with open('test.txt') as f:
    print f.readlines()

1. quel gestionnaire de contexte?

Grammaire de base

with EXPR as VAR:
    BLOCK

Clarifiez d'abord quelques concepts

1. 上下文表达式:with open('test.txt') as f:
2. 上下文管理器:open('test.txt')
3. f 不是上下文管理器,应该是资源对象。

2. comment le gestionnaire de contexte?

Pour implémenter vous-même une telle gestion de contexte, vous devez d'abord connaître le protocole de gestion de contexte.

Pour faire simple, la méthode __enter__and __exit__est implémentée dans une classe et une instance de cette classe est un gestionnaire de contexte.

Par exemple cet exemple:

class Resource():
    def __enter__(self):
        print('===connect to resource===')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('===close resource connection===')

    def operate(self):
        print('===in operation===')

with Resource() as res:
    res.operate()

Exécutons-le et parcourons la séquence d'impression du journal. Vous pouvez connaître le processus d'exécution.

===connect to resource===
===in operation===
===close resource connection===

À partir de cet exemple, il est évident que lors de l'écriture de code, vous pouvez placer la connexion ou l'acquisition de __enter__la ressource et écrire la clôture de la ressource __exit__.

3. pourquoi le gestionnaire de contexte?

Demandez-vous encore quelques raisons lorsque vous étudiez et développez une réflexion sur certains détails, ce qui vous aidera à approfondir votre compréhension des points de connaissance.

Pourquoi utiliser un gestionnaire de contexte?

À mon avis, cela est lié au style élégant prôné par Python.

  1. Vous pouvez manipuler (créer / acquérir / libérer) les ressources d'une manière plus élégante, comme les opérations sur les fichiers et les connexions aux bases de données;
  2. Vous pouvez gérer les exceptions de manière plus élégante;

Le premier, nous avons déjà pris la connexion de ressources comme exemple.

Le deuxième type sera ignoré par la plupart des gens. Je vais me concentrer là-dessus ici.

Comme nous le savons tous, la gestion des exceptions est généralement utilisée try...execept..pour capturer le processus. Un inconvénient de ceci est qu'il y aura un grand nombre d'agents de gestion d'exceptions dans la logique principale du code, ce qui affectera grandement notre lisibilité.

Une petite meilleure chose à faire, peut être utilisée withpour gérer les exceptions cachées.

Toujours sur la base de l'exemple de code ci-dessus, nous allons 1/0ceci 一定会抛出异常的代码écrit operateen

class Resource():
    def __enter__(self):
        print('===connect to resource===')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('===close resource connection===')
        return True

    def operate(self):
        1/0

with Resource() as res:
    res.operate()

Après l'avoir exécuté, j'ai été surpris de constater qu'aucune erreur n'a été signalée.

C'est un aspect puissant du protocole de gestion de contexte. Les exceptions peuvent __exit__être interceptées et vous pouvez décider comment les gérer, que ce soit pour le lancer ou pour le résoudre ici. En __exit__retour True(pas de retour à la valeur par défaut pour retourner False), équivalent à dire à l'interpréteur Python, nous avons capturé l'exception, vous n'avez pas besoin de la jeter.

Lors de l'écriture d'une __exit__fonction, vous devez y prêter attention. Elle doit avoir ces trois paramètres:

  • exc_type: type d'exception
  • exc_val: valeur anormale
  • exc_tb: informations de pile d'erreurs anormales

Lorsque le code logique principal ne signale pas d'exception, ces trois paramètres seront tous Aucun.

4. comment contextlib?

Dans l'exemple ci-dessus, nous venons d'écrire une classe pour créer un gestionnaire de contexte. Si vous souhaitez simplement implémenter une fonction simple, écrire une classe est un peu trop compliqué. A ce moment, nous avons pensé, si une seule fonction peut être écrite pour implémenter le gestionnaire de contexte.

Python a longtemps pensé à ce point. Il nous fournit un décorateur.Vous pouvez transformer cet objet fonction en gestionnaire de contexte tant que vous implémentez le contenu de la fonction selon son protocole de code.

Nous suivons le protocole contextlib pour implémenter un gestionnaire de contexte pour l'ouverture des fichiers (avec open).

import contextlib

@contextlib.contextmanager
def open_func(file_name):
    # __enter__方法
    print('open file:', file_name, 'in __enter__')
    file_handler = open(file_name, 'r')

    # 【重点】:yield
    yield file_handler

    # __exit__方法
    print('close file:', file_name, 'in __exit__')
    file_handler.close()
    return

with open_func('/Users/MING/mytest.txt') as file_in:
    for line in file_in:
        print(line)

Dans la fonction décorée, il doit s'agir d'un générateur (avec yield), et le code avant yield est équivalent __enter__au contenu à l'intérieur. Le code après yield équivaut __exit__au contenu dans.

Le code ci-dessus ne peut atteindre que le premier objectif du gestionnaire de contexte (gérer les ressources), mais pas le second (gérer les exceptions).

Si vous souhaitez gérer des exceptions, vous pouvez le modifier comme suit.

import contextlib

@contextlib.contextmanager
def open_func(file_name):
    # __enter__方法
    print('open file:', file_name, 'in __enter__')
    file_handler = open(file_name, 'r')

    try:
        yield file_handler
    except Exception as exc:
        # deal with exception
        print('the exception was thrown')
    finally:
        print('close file:', file_name, 'in __exit__')
        file_handler.close()

        return

with open_func('/Users/MING/mytest.txt') as file_in:
    for line in file_in:
        1/0
        print(line)

Il semble que tant que le gestionnaire de contexte est mentionné, la plupart des gens parleront de l'exemple classique de l'ouverture de fichiers.

Mais dans le développement réel, il existe de nombreux exemples de gestionnaires de contexte qui peuvent être utilisés. Permettez-moi de donner un exemple du mien.

Dans OpenStack, lorsque vous créez un instantané d'une machine virtuelle, vous devez créer un dossier temporaire pour stocker l'image instantanée locale. Une fois l'image instantanée locale créée, téléchargez l'image dans Glance. Supprimez ensuite ce répertoire temporaire.

La logique principale de ce code est 创建快照, et 创建临时目录appartient à la condition préalable 删除临时目录, est la touche finale.

Bien que la quantité de code soit faible et que la logique ne soit pas compliquée, la 创建临时目录,使用完后再删除临时目录fonction " " est nécessaire à de nombreux endroits d'un projet. Si ce traitement logique peut être écrit comme une fonction d'outil en tant que gestionnaire de contexte, le code réutilise Le taux est également grandement amélioré.

Le code est comme ça

En résumé, l'utilisation d'un gestionnaire de contexte présente trois avantages:

  1. Améliorer le taux de réutilisation du code;
  2. Améliorer l'élégance du code;
  3. Améliorer la lisibilité du code;

Je recommande mon e-book original " PyCharm Chinese Guide ", qui contient un grand nombre (300) d'illustrations, il est bien fait et digne d'une collection par chaque ingénieur Python.

L'adresse est: http://pycharm.iswbm.com

Je suppose que tu aimes

Origine blog.csdn.net/weixin_36338224/article/details/108994968
conseillé
Classement