[Route vers Python intermédiaire] Spécifiez dynamiquement la méthode d'exécution par nom de variable

Lien vers le résumé

https://qiita.com/ganariya/items/fb3f38c2f4a35d1ee2e8

introduction

Afin d'étudier Python, j'ai copié une bibliothèque d'intelligence de groupe appelée acopy.

Dans acopy, de nombreuses grammaires et idiomes Python intéressants sont utilisés, et il est résumé que c'est pratique parmi eux.

Cette fois, nous nous concentrerons sur la spécification dynamique de la méthode d'exécution par nom de variable.

getattr

Il existe une fonction intégrée appelée getattr en Python.

Vous pouvez récupérer la méthode de l'instance avec getattr (instance, nom de méthode de l'instance).

Pour l'instant, essayons un exemple simple.


class A:

    def __init__(self, msg):
        self.msg = msg

    def hello(self):
        print("hello ", self.msg)

    def add(self, x, y):
        return x + y


'''
hello  world
7
'''
a = A("world")
getattr(a, 'hello')()
print(getattr(a, 'add')(2, 5))

Écrivons un code source simple comme celui ci-dessus. L'instance a est générée à partir de la classe A getattr (a, 'hello') obtient la méthode de l'attribut hello de l'instance a.

Ensuite, en ajoutant () après cela, la méthode extraite est effectivement exécutée.

Version avancée

Jetons un coup d'œil à l'application réelle de getattr.

Cette fois, vous avez décidé de créer une bibliothèque de classes appelée Library. (Balle droite) Dans la bibliothèque, un traitement unique est exécuté par une fonction appelée run, et les informations internes sont stockées dans une variable membre appelée library_information pour le moment.

À ce stade, vous avez également décidé de distribuer un ** plug-in ** qui vous donne accès aux informations internes de la bibliothèque pour les autres utilisateurs qui souhaitent utiliser la bibliothèque.

Puisqu'il s'agit d'une bibliothèque que vous avez créée, vous seul pouvez implémenter le processus principal, mais en préparant un processus pour exécuter le plugin dans la fonction d'exécution, les utilisateurs qui souhaitent utiliser les informations internes de la bibliothèque peuvent créer leur propre plugin et plus Il peut être étendu.

Regardons en fait le code.

class Library:

    def __init__(self):
        self.plugins = []

        self.library_information = {
            'a': 10,
            'b': 20,
            'c': 30
        }

    def run(self):

        # plugin start
        self.call_plugins('start')

        for cycle in range(3):
            print("Library main process (Mise en œuvre omise)")

            # plugin iteration
            self.call_plugins('iteration')

        # plugin finish
        self.call_plugins('finish')

    def call_plugins(self, hook):
        for plugin in self.plugins:
            plugin(hook, **self.library_information)

    def add_plugin(self, plugin):
        self.plugins.append(plugin)


class Plugin:

    def __init__(self):
        pass

    def __call__(self, hook, **kwargs):
        getattr(self, f'on_{hook}')(**kwargs)

    def on_start(self, **kwargs):
        print(kwargs['a'])

    def on_iteration(self, **kwargs):
        print(kwargs['b'])

    def on_finish(self, **kwargs):
        print(kwargs['c'])


library = Library()
library.add_plugin(Plugin())
library.run()
'''
10
Library main process (Mise en œuvre omise)
20
Library main process (Mise en œuvre omise)
20
Library main process (Mise en œuvre omise)
20
30
'''

Classe de bibliothèque

La bibliothèque est une bibliothèque que vous souhaitez créer et publier sur PyPI, etc. Par exemple, soyez conscient de Numpy et Matplotlib.

Je voulais préparer quelque chose appelé «library_information» dans les informations internes de la bibliothèque afin qu'il puisse être utilisé et étendu par des utilisateurs tiers. Par conséquent, ** Préparez un tableau de plugins en tant que variable membre, héritez de la classe Plugin et transmettez-la à add_plugin afin que le plugin puisse être exécuté. Lorsque le plugin est exécuté à partir de la bibliothèque, les informations internes de la bibliothèque sont transmises, de sorte que l'utilisateur peut étendre la fonction. ** **

Classe de plug-in

Cette fois, il est implémenté avec print, mais à l'origine, c'est une classe abstraite et vous créez également ce plugin, et l'utilisateur crée le plugin original en héritant davantage de ce plugin.

En préparant une fonction __call__, vous pouvez l'exécuter comme une fonction.

Utilisez getattr lorsque vous appelez __call__. Cela amène le côté bibliothèque à exécuter l'instance de plug-in lors de l'exécution et à transmettre les informations de bibliothèque à ce moment-là. Ensuite, l'instance de Plugin est getattr, qui fait ressortir la fonction qui correspond au hook start, finish, iteration approprié dans l'exécution et l'utilise.

Dans la fonction exécutée, vous pouvez également supprimer getattr comme call_plugins_start, call_plugins_finish et écrire tous les cas séparément, mais cela vous permet d'écrire de manière unifiée.

Extensibilité de la bibliothèque

En préparant une classe de plug-in avec la bibliothèque et en la distribuant aux utilisateurs

--Passez les informations de la bibliothèque du côté bibliothèque vers le plug-in

Il y a des avantages. Cependant, sachez que le risque d'erreurs d'exécution augmente car vous ne savez pas s'il est correct tant que vous ne l'exécutez pas.

Recommended Posts

[Route vers Python intermédiaire] Spécifiez dynamiquement la méthode d'exécution par nom de variable
Une route vers Python intermédiaire
[Road to Intermediate] Comprendre les propriétés Python
[Route vers Python intermédiaire] Utiliser des opérateurs ternaires
[Route vers Python intermédiaire] Utiliser des expressions lambda
[Route vers Python intermédiaire] Résumé du lien de l'article
Pour remplacer dynamiquement la méthode suivante en python
[Road to Intermediate] Python semble être tous des objets
Comment obtenir le nom de la variable lui-même en python
[Route vers Python intermédiaire] Définir la fonction __getattr__ dans la classe
[Road to Intermediate Python] Définissez dans votre propre classe
[Road to Intermediate Python] Installer des packages en masse avec pip
[Python] Comment définir des noms de variables dynamiquement et comparer la vitesse
[Route vers Python intermédiaire] Utiliser l'instruction if dans la notation d'inclusion de liste
[Road to Intermediate Python] Permet des opérations de comparaison pour des classes uniques
Comment remplacer une méthode de type défini par l'utilisateur générée par python swig
[Road to Intermediate Python] Appelez une instance de classe comme une fonction avec __call__
Exécution par sous-shell (et mise à jour des variables)
[Python] Road to the Serpent (3) Classe Python
Road to Intermediate Linux: Network Edition
Python (de la première fois à l'exécution)