2010-04-08 2 views

Répondre

6

Non. Vous pouvez accéder à Foo.__dict__ et appeler chaque valeur l'une après l'autre (erreurs de saisie pour les membres non appelables), mais l'ordre n'est pas conservé.

for callable in Foo.__dict__.values(): 
    try: 
     callable()  
    except TypeError: 
     pass 

Ceci suppose qu'aucune des fonctions n'accepte de paramètres, comme dans votre exemple.

5

Puisque Python stocke les méthodes (et d'autres attributs) d'une classe dans un dictionnaire, qui est fondamentalement non ordonné, c'est impossible.

Si vous ne se soucient pas de l'ordre, utilisez __dict__ de la classe:

x = Foo() 
results = [] 
for name, method in Foo.__dict__.iteritems(): 
    if callable(method): 
     results.append(method(x)) 

Cela fonctionne également si la fonction prend des paramètres supplémentaires - il suffit de les mettre une fois l'instance de la classe.

+0

Un moyen de le faire si je ne me soucie pas de la commande? – curious

+0

Bien sûr, je vais modifier la réponse. –

8
def assignOrder(order): 
    @decorator 
    def do_assignment(to_func): 
    to_func.order = order 
    return to_func 
    return do_assignment 

class Foo(): 

    @assignOrder(1) 
    def bar(self): 
    print "bar" 

    @assignOrder(2) 
    def foo(self): 
    print "foo" 

    #don't decorate functions you don't want called 
    def __init__(self): 
    #don't call this one either! 
    self.egg = 2 

x = Foo() 
functions = sorted(
      #get a list of fields that have the order set 
      [ 
       getattr(x, field) for field in dir(x) 
       if hasattr(getattr(x, field), "order") 
      ], 
      #sort them by their order 
      key = (lambda field: field.order) 
      ) 
for func in functions: 
    func() 

drôle ligne @assignOrder(1) ci-dessus def bar(self) déclenche que cela se produise:

Foo.bar = assignOrder(1)(Foo.bar) 

assignOrder(1) retourne une fonction qui prend une autre fonction, le change (en ajoutant le champ order et la mise à 1) et le renvoie . Cette fonction est ensuite appelée sur la fonction qu'elle décore (son champ order est ainsi positionné); le résultat remplace la fonction d'origine.

Il est un colombophile, plus lisible et plus moyen maintenable de dire:

def bar(self): 
    print "bar" 
    Foo.bar.order = 1 
+0

+1 - Wow - excellente utilisation des décorateurs de fonction! –

+2

Essayez de ne pas utiliser 'eval' si possible. Quelque chose comme ça devrait fonctionner: '[getattr (x, champ) pour le champ dans dir (x) si hasattr (getattr (x, champ), 'order')]' –

+0

Je savais qu'il devait y avoir une meilleure façon :) – badp

1

Tant que vous n'êtes intéressé que par 3.x Python (et des parenthèses vides dans votre déclaration de classe je vais devinez que vous pourriez être), alors il ya une manière simple de le faire sans décorateurs: Python 3 vous permet de fournir votre propre dictionnaire comme objet à utiliser pendant que la classe est définie.

Le code suivant est de PEP3115, sauf pour les deux dernières lignes que j'ajouté d'imprimer les méthodes pour:

# The custom dictionary 
class member_table(dict): 
    def __init__(self): 
    self.member_names = [] 

    def __setitem__(self, key, value): 
    # if the key is not already defined, add to the 
    # list of keys. 
    if key not in self: 
     self.member_names.append(key) 

    # Call superclass 
    dict.__setitem__(self, key, value) 

# The metaclass 
class OrderedClass(type): 

    # The prepare function 
    @classmethod 
    def __prepare__(metacls, name, bases): # No keywords in this case 
     return member_table() 

    # The metaclass invocation 
    def __new__(cls, name, bases, classdict): 
     # Note that we replace the classdict with a regular 
     # dict before passing it to the superclass, so that we 
     # don't continue to record member names after the class 
     # has been created. 
     result = type.__new__(cls, name, bases, dict(classdict)) 
     result.member_names = classdict.member_names 
     return result 

class MyClass(metaclass=OrderedClass): 
    # method1 goes in array element 0 
    def method1(self): 
    pass 

    # method2 goes in array element 1 
    def method2(self): 
    pass 

x = MyClass() 
print([name for name in x.member_names if hasattr(getattr(x, name), '__call__')]) 
1

Il est probablement l'une des méthodes les plus courtes (le nom de classe est C):

for func in filter(lambda x: callable(x), C.__dict__.values()): 
    pass # here func is the next function, you can execute it here 

le filtre expression renvoie toutes les fonctions de la classe C.

OU en une ligne:

[func() for func in filter(lambda x: callable(x), C.__dict__.values())] 

Vous pouvez commander en quelque sorte les fonctions, par exemple, par ordre lexicographique de leur nom par peu d'expression plus complexe.

Questions connexes