7
votes

Improduction d'un remplacement de goutte pour la déclaration "avec" pour Python 2.4

Pouvez-vous suggérer un moyen de coder un remplacement déroulant de la déclaration "avec" qui fonctionnera dans Python 2.4?

Ce serait un hack, mais cela me permettrait de porter mon projet à Python 2.4 plus gentiment.

EDIT: Sketch de métaclass non pertinent enlevé


1 commentaires

Aucune approche de classe Comme vous imaginez peut fonctionner - la métaclasse est appelée après que le corps de classe se termine normalement et n'a aucune chance d'intercepter des exceptions soulevées dans le corps de la classe.


5 Réponses :


4
votes

Vous pouvez (AB) utiliser des décorateurs pour le faire, je pense. Les travaux suivants, par exemple: xxx pré>

(puits, dans Python 2.4 Les objets de fichier n'ont pas __enter__ et __exit__ méthodes, mais sinon cela fonctionne) p>

L'idée est que vous 'RE REMPLACEMENT DE LA LIGNE IN: P>

@execute_with_context_manager( bar() )
def dummyname( foo ):
    do_something_with(foo)
    do_something_else_with(foo)
    # etc...


9 commentaires

Ce n'est pas vraiment une chute de remplacement, car cela suppose que le code est une fonction, alors qu'il pourrait être juste quelques lignes de code. Et avoir à le compromettre dans une fonction serait trop gênant.


N'est-ce pas avec expression [comme Varname]:


@ Cool-RR L'emballage de la fonction est juste une syntaxe pour séparer le code à l'intérieur du code de l'extérieur, comme la classe de la question.


Votre code pourrait être partiellement fixé en effectuant en réalité la fonction dans le décorateur. Cela rendrait un peu plus semblable à la structure de "avec", sauf que la vôtre a une ligne supplémentaire, la ligne @. Je suppose que si aucune meilleure solution ne se présente, je vais le prendre.


@ Cool-RR Le décorateur invoque la fonction qu'il décorait - c'est la ligne F (homme)


Vous l'appelez à l'intérieur de la fonction décorée, mais pas dans le décorateur lui-même. De cette façon, vous devriez réellement appeler la fonction après la définition, qui n'est indésirable. Mieux vaut que le décorateur appelait juste la fonction elle-même.


@ cool-rr @foo (bar) / def Baz (...): - invoque Baz = (FOO (Bar)) (Baz) - Vous devez donc renvoyer une fonction qui est ensuite immédiatement invoquée.


Si vous ne voulez pas faire le bloc dans une fonction, je pense qu'un essai / sauf / enfin est la meilleure solution. Ne vois pas ce qui est si horrible avec cette solution que vous souhaitez simuler un gestionnaire de contexte de toute façon. :)


Ok anthony, je vois mon erreur. Maintenant, ma seule question est pourquoi avez-vous modifié le code de la PEP?



1
votes

Depuis que vous devez quitter le gestionnaire de contexte lors des erreurs et non des erreurs, je ne pense pas qu'il soit possible de faire une usecase générique avec des métaclasses ou du tout. Vous allez avoir besoin d'essayer / enfin des blocages pour cela.

Mais peut-être qu'il est possible de faire autre chose dans votre cas. Cela dépend de ce que vous utilisez le gestionnaire de contexte pour.

à l'aide de __ del __ peut aider dans certains cas, comme la ressource de translocation, mais que vous ne pouvez pas être sûr qu'il est appelé, il ne peut être utilisé que de vous devez libérer des ressources que sera libéré lorsque le programme sort. Cela ne fonctionnera pas non plus si vous manipulez des exceptions dans la méthode __ __ .

Je suppose que la méthode la plus propre consiste à envelopper la gestion du contexte entière dans une sorte de contexte de gestion de contexte, et extraire le bloc de code dans une méthode. Quelque chose comme ça (code non testé, mais surtout volé de PEP 343): xxx


0 commentaires

7
votes

Utilisez simplement try-enfin.

Vraiment, cela peut être agréable comme un exercice mental, mais si vous le faites dans le code, vous vous souciez de vous retrouverez avec le code laid, difficile à maintenir.


0 commentaires

1
votes

Comment de cela? XXX PRE>

Utilisation: P>

@improvize_context_manager(my_lock=lock)
def null(my_lock):
    do(stuff_with, my_lock)


2 commentaires

Je viens de comprendre que cela ne fonctionnera pas, pas plus que la suggestion d'Anthony. Parce que si vous essayez de retourner quelque chose à l'intérieur de la "fonction", vous ne reviendriez pas vraiment dans le bloc extérieur.


C'est vraiment correct, car ce n'est pas une vraie fonction. Vous utilisez simplement la fonction de périphérique syntaxique. Personne ne devrait jamais l'appeler de toute façon. En fait, je ferais del null juste après la définition, juste pour vous assurer.



1
votes

Si vous acceptez d'utiliser DEF juste pour obtenir un bloc, et des décorateurs qui exécutent immédiatement, vous pouvez utiliser la signature de fonction pour obtenir quelque chose de plus naturel pour le cas nommé.

import sys
def with(func):
    def decorated(body = func):
        contexts = body.func_defaults
        try:
            exc = None, None, None
            try:
                for context in contexts:
                    context.__enter__()
                body()
            except:
                exc = sys.exc_info()
                raise
        finally:
            for context in reversed(contexts):
                context.__exit__(*exc)
    decorated()

class Context(object):
    def __enter__(self):
        print "Enter %s" % self
    def __exit__(self, *args):
        print "Exit %s(%s)" % (self, args)

x = Context()

@with
def _(it = x):
    print "Body %s" % it

@with
def _(it = x):
    print "Body before %s" % it
    raise "Nothing"
    print "Body after %s" % it


0 commentaires