50 votes

passer l'argument à __enter__

Je me renseigne sur les déclarations notamment de cet article

La question est de savoir si je peux passer un argument à __enter__ ?

J'ai un code comme celui-ci :

class clippy_runner:
    def __enter__(self):
        self.engine = ExcelConnection(filename = "clippytest\Test.xlsx")
        self.db = SQLConnection(param_dict = DATASOURCES[STAGE_RELATIONAL])

        self.engine.connect()
        self.db.connect()

        return self

Je voudrais passer le nom du fichier et le dictionnaire de paramètres comme paramètres à __enter__ . Est-ce possible ?

1voto

Carson Arucard Points 334

Je pense que pour utiliser le contextlib.contextmanager (paquet natif) est une bonne idée.

Pour plus de détails, voir ce qui suit.

un exemple simple

from contextlib import contextmanager

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

    def say_something(self, msg):
        print(f'{self.name}: {msg}')

    @staticmethod
    @contextmanager
    def enter(name,  # <-- members of construct
              para_1, options: dict  # <-- Other parameter that you wanted.
              ):
        with Person(name) as instance_person:
            try:
                print(para_1)
                print(options)
                yield instance_person
            finally:
                ...

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

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

with Person.enter('Carson', para_1=1, options=dict(key='item_1')) as carson:
    carson.say_something('age=28')
    print('inside')
print('outside')

sortie

Carson
1
{'key': 'item_1'}
Carson: age=28
inside
__exit__
outside

votre exemple

from typing import Union
from contextlib import contextmanager

def main():
    with ClippyRunner.enter(filename="clippytest/Test.xlsx",
                            param_dict='DATASOURCES[STAGE_RELATIONAL]') as clippy_runner:
        clippy_runner.do_something()

class ConnectBase:
    def connect(self):
        print(f'{type(self).__name__} connect')

    def disconnect(self):
        print(f'{type(self).__name__} disconnect')

class ExcelConnection(ConnectBase):
    def __init__(self, filename):
        self.filename = filename

class SQLConnection(ConnectBase):
    def __init__(self, param_dict):
        self.param_dict = param_dict

class ClippyRunner:
    def __init__(self, engine: Union[ExcelConnection], db: Union[SQLConnection]):
        self.engine = engine
        self.db = db

    def do_something(self):
        print('do something...')

    @staticmethod
    @contextmanager
    def enter(filename, param_dict):
        with ClippyRunner(ExcelConnection(filename),
                          SQLConnection(param_dict)) as cr:
            try:
                cr.engine.connect()
                cr.db.connect()
                yield cr
            except:
                cr.release()  # disconnect
            finally:
                ...

    def __enter__(self):
        return self

    def release(self):
        self.engine.disconnect()
        self.db.disconnect()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.release()

if __name__ == '__main__':
    main()

sortie

ExcelConnection connect
SQLConnection connect
do something...
ExcelConnection disconnect
SQLConnection disconnect

À propos de contextmanager

Un gestionnaire de contexte fait (fondamentalement) trois choses :

  1. Il exécute du code avant un bloc de code.
  2. Il exécute du code après un bloc de code.
  3. En option, il supprime les exceptions soulevées dans un bloc de code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X