2010-04-08 6 views

Antwort

6

Nein. Sie können auf Foo.__dict__ zugreifen und jeden Wert der Reihe nach aufrufen (Fehler für nicht aufrufbare Mitglieder abfangen), aber die Reihenfolge wird nicht beibehalten.

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

Dies setzt voraus, dass keine der Funktionen Parameter wie in Ihrem Beispiel verwendet.

5

Da Python die Methoden (und andere Attribute) einer Klasse in einem Wörterbuch speichert, das grundlegend ungeordnet ist, ist dies unmöglich.

Wenn Sie Bestellung nicht egal, verwenden Sie die Klasse __dict__:

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

Dies funktioniert auch, wenn die Funktion zusätzliche Parameter nimmt - sie kurz nach der Instanz der Klasse setzen.

+0

Jede Art und Weise, es zu tun, wenn ich über den Auftrag nicht kümmern? – curious

+0

Sicher, ich werde die Antwort bearbeiten. –

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() 

Das lustige @assignOrder(1) Linie über def bar(self) löst dies geschehen kann:

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

assignOrder(1) gibt eine Funktion, die eine andere Funktion übernimmt, ändert sich (Hinzufügen des Feldes order und es 1 Einstellung) und gibt es . Diese Funktion wird dann für die Funktion aufgerufen, die sie dekoriert (ihr order Feld wird also gesetzt); Das Ergebnis ersetzt die ursprüngliche Funktion.

Es ist eine schicke, lesbare und wartbare Art zu sagen:

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

+1 - Wow - ausgezeichnete Verwendung von Funktion Dekorateure! –

+2

Versuchen Sie nicht, eval zu verwenden, wenn möglich. So etwas sollte funktionieren: '[getattr (x, Feld) für das Feld in dir (x), wenn hasattr (getattr (x, Feld), 'bestellen')]' –

+0

ich wusste, dass es einen besseren Weg sein :) – badp

1

So lange, wie Sie in Python 3.x nur daran interessiert sind (und von den leeren Klammern in Ihrer Erklärung Klasse Ich werde Ich nehme an, Sie könnten es sein), dann gibt es tatsächlich eine einfache Möglichkeit, dies ohne Dekoratoren zu tun: Python 3 ermöglicht es Ihnen, Ihr eigenes Wörterbuch wie ein Objekt zur Verfügung zu stellen, während die Klasse definiert ist.

Der folgende Code aus PEP3115 ist bis auf den letzten paar Zeilen, die ich aus den Verfahren zu drucken, um das hinzugefügt:

# 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

Es gibt wohl eine der kürzesten Methoden (der Klassenname ist C):

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

der Filter Ausdruck liefert alle Funktionen der Klasse C.

OR in einer Zeile:

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

Sie können etwas komplexer Ausdruck irgendwie die Funktionen, beispielsweise durch lexikographische Reihenfolge ihrer Namen bestellen.

Verwandte Themen