2009-10-13 8 views
3

J'écris un programme qui utilise des techniques génétiques pour faire évoluer des équations. Je veux être en mesure de soumettre la fonction 'mainfunc' à la fonction 'soumettre' de Python parallèle. La fonction 'mainfunc' appelle deux ou trois méthodes définies dans la classe Utility. Ils instancient d'autres classes et appellent diverses méthodes. Je pense que ce que je veux, c'est tout dans un NAMESPACE. J'ai donc instancié quelques-unes (peut-être toutes les classes) dans la fonction 'mainfunc'. J'appelle la méthode utilitaire 'generate()'. Si nous devions suivre sa chaîne d'exécution , cela impliquerait toutes les classes et méthodes du code.Structurer un programme. Classes et fonctions en Python

Maintenant, les équations sont stockées dans un arbre. Chaque fois qu'un arbre est généré, muté ou croisé, les noeuds doivent recevoir une nouvelle clé afin qu'ils puissent être accédés à partir d'un attribut de dictionnaire de l'arbre. La classe 'KeySeq' génère ces clés.

En Parallèle Python, je vais envoyer plusieurs instances de 'mainfunc' à la fonction 'submit' de PP. Chacun doit pouvoir accéder à 'KeySeq'. Ce serait bien si tous avaient accès à la même instance de KeySeq, de sorte qu'aucun des nœuds des arbres retournés n'avait la même clé, mais je pourrais contourner cela si nécessaire. Donc: ma question concerne le bourrage de tout dans Mainfunc. Merci (Edit) Si je n'inclus pas tout dans mainfunc, je dois essayer de dire à PP sur les fonctions dépendantes, etc. en faisant passer diverses argumentations à divers endroits. J'essaie d'éviter ça.

(fin Edit) si ks.next() est appelée dans la « fonction generate(), il renvoie l'erreur 'NameError: nom global 'ks' est pas défini'

class KeySeq: 
    "Iterator to produce sequential \ 
    integers for keys in dict" 
    def __init__(self, data = 0): 
     self.data = data 
    def __iter__(self): 
     return self 
    def next(self): 
     self.data = self.data + 1 
     return self.data 
class One: 
    'some code' 
class Two: 
    'some code' 
class Three: 
    'some code' 
class Utilities: 
    def generate(x): 
     '___________' 
    def obfiscate(y): 
     '___________' 
    def ruminate(z): 
     '__________' 


def mainfunc(z): 
    ks = KeySeq() 
    one = One() 
    two = Two() 
    three = Three() 
    utilities = Utilities() 
    list_of_interest = utilities.generate(5) 
    return list_of_interest 

result = mainfunc(params) 

Répondre

1

Si vous voulez que tous les cas de mainfunc d'utiliser le même objet KeySeq, vous pouvez utiliser l'astuce de la valeur du paramètre par défaut:

def mainfunc(ks=KeySeq()): 
    key = ks.next() 

Tant que vous ne passez pas réellement une valeur de ks , tous les appels à mainfunc utiliseront l'instance de KeySeq créée lors de la définition de la fonction.

Voici pourquoi, au cas où vous ne le sauriez pas: Une fonction est un objet. Il a des attributs. Un de ses attributs est nommé func_defaults; c'est un tuple contenant les valeurs par défaut de tous les arguments de sa signature qui ont des valeurs par défaut. Lorsque vous appelez une fonction et ne fournissez pas de valeur pour un argument ayant une valeur par défaut, la fonction extrait la valeur de func_defaults. Ainsi, lorsque vous appelez mainfunc sans fournir de valeur pour ks, l'instance KeySeq() est extraite du tuple func_defaults. Lequel, pour cette instance de mainfunc, est toujours la même instance KeySeq.

Maintenant, vous dites que vous allez envoyer "plusieurs instances de mainfunc à la fonction submit de PP."Voulez-vous vraiment dire plusieurs instances? Si oui, le mécanisme que je décris ne fonctionnera pas

Mais il est difficile de créer plusieurs instances d'une fonction (et le code que vous avez posté ne fonctionne pas). par exemple, cette fonction ne retourne une nouvelle instance de g chaque fois qu'il est appelé.

>>> def f(): 
     def g(x=[]): 
      return x 
     return g 
>>> g1 = f() 
>>> g2 = f() 
>>> g1().append('a') 
>>> g2().append('b') 
>>> g1() 
['a'] 
>>> g2() 
['b'] 

Si j'appelle g() sans argument, elle renvoie la valeur par défaut (d'abord une liste vide) de son tuple func_defaults depuis g1 et g2 sont des instances différentes de la fonction g, leur valeur par défaut pour l'argument x est également une instance différente, ce qui est démontré ci-dessus.

Si vous souhaitez rendre plus explicite que d'utiliser un effet secondaire délicat des valeurs par défaut, voici une autre façon de le faire:

def mainfunc(): sinon hasattr (mainfunc, « ks «): setattr (mainfunc, "ks", suite_de_touches()) key = mainfunc.ks.next()

Enfin, un point super important que le code que vous avez posté belvédères: Si vous allez Pour effectuer un traitement parallèle sur des données partagées, le code qui touche ces données doit implémenter le verrouillage. Regardez l'exemple callback.py dans la documentation de Parallel Python et voyez comment le verrouillage est utilisé dans la classe Sum, et pourquoi.

+0

J'ai essayé de brancher votre 'tour de paramètre par défaut'. Une erreur s'est produite dans la méthode 'utilities.generate(): a = key "NameError: nom global' clé 'n'est pas défini" J'ai vérifié que' mainfunc (ks = KeySeq()) 'a été appelé sans aucune paramètres. En ce moment j'essaye de faire fonctionner ceci sans référence à PP. Cependant, j'étudierai la deuxième moitié de votre message. Et je ferai référence à callback.py avant d'introduire PP. –

+0

J'ai aussi essayé la seconde méthode proposée, la plus explicite. Il a produit la même erreur dans la même méthode 'utilities.generate(). –

+1

Il semble que vous soyez sous l'impression que 'key' est visible en dehors de la fonction' mainfunc'. Il ne sera pas disponible pour 'Utilities.generate()' à moins que vous ne fassiez quelque chose pour le rendre - faites-en un argument de la fonction 'generate', disons, ou passez-le dans le constructeur, ou fixez un attribut sur le' L'objet Utilities après l'avoir instancié. Ou en faire une variable au niveau du module et la référencer en utilisant 'global'. Il y a des dizaines de façons de le faire, mais vous devez en utiliser une. –

3

Il est bien de structurez votre programme de cette façon. Beaucoup d'utilitaires en ligne de commande suivent le même schéma:

#imports, utilities, other functions 

def main(arg): 
    #... 

if __name__ == '__main__': 
    import sys 
    main(sys.argv[1]) 

De cette façon, vous pouvez appeler la fonction main d'un autre module en importer, ou vous pouvez l'exécuter à partir de la ligne de commande.

+0

Noté. Merci –

0

Votre concept de classes en Python n'est pas sain je pense. Peut-être, ce serait une bonne idée de revoir les bases. Ce lien vous aidera.

Python Basics - Classes

+0

Vous avez raison. Merci pour le lien –

Questions connexes