2017-05-11 1 views
0

j'ai tout à fait quelques fonctions qui utilise des variables globales pour tenir un objet pour être réutilisés dans toute la bibliothèque, par exemple:Création d'un décorateur/cache pour le contrôle variable globale

from some.other.lib import Object1, Object2, Object3, Object4, Object5 

def function1(input): 
    global _object1 
    try: 
     _object1 
    except NameError: 
     _object1 = Object1 
    return _object1.func1(input) 


def function2(input): 
    global _object2 
    try: 
     _object2 
    except NameError: 
     _object2 = Object2 
    # Use function1 to do something to the input 
    return _object2.func2(function1(input)) 


def function3(input): 
    global _object3 
    try: 
     _object3 
    except NameError: 
     _object3 = Object3 
    # Use function1 to do something to the input. 
    return _object3.func3(function1(input)) 


def function4(input): 
    global _object4 
    try: 
     _object4 
    except NameError: 
     _object4 = Object4 
    return _object4.func4(input) 


def function5(input): 
    global _object5 
    try: 
     _object5 
    except NameError: 
     _object5 = Object5 
    # Use function4 to do something to the input. 
    return _object5.func5(function4(input)) 

Est-il possible d'écrire un décorateur tel que le code pour vérifier la variable globale n'a pas besoin d'être codé en dur manuellement pour chacun des function*?

E.g. quelque chose comme:

def exist_decorator(_object, _class): 
    try: 
     _object 
    except NameError: 
     _object = _class 
    return _object 

Ainsi, la mise en œuvre de classe réelle pour function4() ressemblera:

def function4(input): 
    global _object4 
    exist_decorator(_object4, Object4) 
    return _object4.func4(input) 

Est-ce quelque chose comme cela syntaxiquement possible en Python avec décorateurs? Sinon, comment puis-je créer un décorateur/cache pour vérifier la variable globale?

+0

Les décorateurs utilisent des fonctions et non des instructions. –

+0

Ai-je raison de supposer que vous abusez simplement des variables globales pour garder une sorte de cache qui n'est utilisé que dans une fonction spécifique? Ou avez-vous l'intention d'utiliser le '_object1' en dehors de la portée de' function1() '? – Alfe

+0

Oui, j'en abuse pour mettre en cache un modèle (plus précisément: https://github.com/alvations/earthy/blob/master/earthy/nltk_wrappers/__init__.py#L27) Mais je pense qu'il doit y avoir un meilleur façon de le faire, mais je ne suis pas sûr de savoir comment découpler le modèle le faire rester dans un cache et quand un utilisateur veut accéder au modèle. – alvas

Répondre

1

Je suppose que vous voulez juste mettre en cache certaines valeurs. Pour cela, l'approche avant droit en Python décent sans abuser aucune fonction cachée est la suivante:

cache = {} 

def function1(input): 
    try: 
     object1 = cache['object1'] 
    except KeyError: 
     object1 = cache['object1'] = Object1 
    return object1.func1(input) 

Et même pour les autres fonctions.

Vous pouvez également éviter d'utiliser la variable globale encore cache en stockant tout ce qui est votre objet de fonction:

def function1(input): 
    try: 
     object1 = function1.object1 
    except AttributeError: 
     object1 = function1.object1 = Object1 
    return object1.func1(input) 

Ceci est possible parce que les fonctions sont des objets quelconques auxquels vous pouvez ajouter des attributs. Mais certains pourraient appeler cela un abus et un code malpropre. Comme toujours dans de tels cas, discutez-en d'abord avec votre équipe et peut-être l'ajouter à la liste des techniques utilisées pour cette équipe ou ce projet avant de l'utiliser.

Je préfère utiliser la fonction cachée des arguments mutables:

def function(input, object1Cache=[None]): 
    if object1Cache[0] is None: 
     object1Cache[0] = Object1 
    return object1Cache[0].func1(input) 

Cela fonctionne en Python, car la liste en tant que valeur par défaut pour un paramètre de fonction est encore mutable et gardera sa valeur. Et encore une fois, cela peut être considéré comme sale et abusif, alors discutez-en avec votre équipe avant de l'utiliser et documentez dans vos notes de projet que cette technique est utilisée.

+0

Utiliserait quelque chose comme https://datascience.blog.wzb.eu/2016/08/12/a-tip-for-the-impatient- simple-cache-avec-python-pickle-et-décorateurs/aide? – alvas

+1

Bien sûr, il existe de nombreuses bibliothèques (ou seulement des fragments de code) pour la mise en cache d'une valeur. La mise en cache dans un fichier Pickle, cependant, signifie le mettre en cache au-delà de l'exécution du processus.La prochaine fois que vous lancerez ce processus, le fichier pickle sera peut-être toujours disponible. Vous n'avez jamais mentionné que vous vouliez cette fonctionnalité, et aucune de mes versions pour la mise en cache ne le fait, donc je mentionne cette implication. – Alfe