2010-12-14 68 views
1

currectly, je suis en train de ce qui suit: Certaines fonctions mutator accepte la portée locale autre fonction à l'aide locals()Comment modifier les variables d'une autre portée?

def mutator(locals): 
    locals['n'] = 10 
    locals['l'].append(10) 

def f(): 
    n = 1 
    l = [1] 
    mutator(locals()) 
    print(n,l) # >>> 1, [1,10] 

f(None) 

et qui fonctionne comme prévu: j'ai pu modifier le contenu de la liste mutables, mais a échoué à « rebind » une autre immuable int au même nom.

Actuellement, je vois quelques options:

  • eval(), exec() & Co
  • Jouer avec des cadres de pile & variables locales dans mutator()
  • Conserver ces variables dans un dict: pas très pratique, mais probablement le meilleur un

La restriction est: cible fu nction f() peut contenir un seul appel de fonction, éventuellement avec des arguments, et cette fonction devrait pouvoir modifier les valeurs dans la portée actuelle f() s.

Alors ... existe-t-il un moyen de réintroduire la valeur de la variable (lier un autre objet) lors de l'exécution? Je ne crois pas qu'il n'y ait pas de bonne astuce pour réaliser cela!


Voici un exemple de la chose que je suis en train de réaliser:

def view(request): # Yes, that's Django! 
    q = MyModel.objects.all() 

    data = { 'some_action': True, 'items_per_page': 50 } # defaults. Mutators can change this 
    mutators.launch(locals(), data) # Launch mutators that may want to narrow the QuerySet 

    if data['some_action']: # do something useful if no mutator has disabled it 
      ... 

    # paginate using data['items_per_page'] 

Je ne veux pas utiliser data dict ici: possibilité de les modifier en tant que variables locales seraient beaucoup mieux & joli. Notez que q objet QuerySet est mutable & Les mutateurs peuvent modifier son contenu.

+0

nécessite plus de formatage. indenter les corps de méthode. – Robert

+6

Qu'essayez-vous exactement d'accomplir? – Falmarri

+0

Cela va être un moyen de réglage externe de la logique interne de la fonction, pour ainsi dire :) Comme changer certains booléens on/off pour activer/désactiver les fonctionnalités, affiner une liste à un sous-ensemble, etc. Je suis sûr que c'est la meilleure façon de mettre en œuvre un bon cadre de réglage et d'extension pour un système hautement personnalisable. – kolypto

Répondre

3
class AttributeCollection(object): 
    pass 
shared_settings= AttributeCollection() 
# now improvise 
shared_settings.temperature= 30 
shared_settings.samples= [] 
# etc 

qui passe shared_settings autour, ou la rendre globale, et définir ses attributs à tout ce que vous désirez. Vous voyez, les locals() d'une fonction sont simplement un espace de noms destiné (et optimisé pour cela) à être manipulé à l'intérieur de cette fonction (et pendant que cette fonction est en cours d'exécution). Utilisez un autre espace de nom (dans ma suggestion, l'objet shared_settings) en tant que terrain de jeu commun pour votre code.

+2

+1 pour encapsuler tout dans une classe. Penser à envoyer vos variables locales dans un blob à quelqu'un d'autre me rend nerveux. – spade78

+0

Juste une chose: y a-t-il une raison d'instancier une classe au lieu d'utiliser 'dict'? Nous allons utiliser son attribut '__dict__' seulement de toute façon – kolypto

+1

@o_O: instancier une classe vous permet d'utiliser la notation par points pour l'accès aux attributs; Si vous utilisez une notation getitem, utilisez un dict. – tzot

0

Est-ce que cette façon:

def mutator(l): 
    l.append(10) 
    return 10 

def f(): 
    n = 1 
    l = [1] 
    n = mutator(l) 
    print(n,l) # >>> 1, [1,10] 

f() 

Ouais, je sais que ce n'est pas la bidouille que vous voulez; mais ça marche. :-)

Si vous voulez un ensemble d'options de configuration globale que vous pouvez activer et affiner, coller tous sur un objet:

class Settings(object): 
    def __init__(self): 
     self.n = 1 
     self.l = [1] 

Maintenant, vous pouvez modifier les variables à votre contenu de coeurs.

+0

:))) bien! Mais cela ne sera pas bien quand j'ai besoin de retourner plusieurs valeurs. À mon humble avis, il est préférable d'utiliser un seul dict: 'self.n 'utilisera' self .__ dict__' de toute façon – kolypto

+1

... Et pourquoi auriez-vous besoin de retourner plusieurs valeurs? Ils sont tous liés dans les paramètres! :) –