2010-04-08 34 views

Respuesta

6

No. Puede acceder al Foo.__dict__, y llamar a cada valor por turno (errores de captura para miembros no llamables), pero el orden no se conserva.

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

Esto asume que ninguna de las funciones toma parámetros, como en su ejemplo.

5

Dado que Python almacena los métodos (y otros atributos) de una clase en un diccionario, que está fundamentalmente desordenado, esto es imposible.

Si no se preocupan por fin, el uso del __dict__ la clase:

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

Esto también funciona si la función de toma parámetros adicionales - sólo hay que poner ellos después de la instancia de la clase.

+0

¿Alguna manera de hacerlo si no me importa el pedido? – curious

+0

Claro, voy a editar la respuesta. –

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

Que divertido @assignOrder(1) línea anterior def bar(self) disparadores que esto suceda:

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

assignOrder(1) devuelve una función que toma otra función, lo cambia (añadiendo el campo order y se establece a 1) y lo devuelve . Esta función se invoca luego en la función que decora (se establece así su campo order); el resultado reemplaza la función original.

Es una manera más elegante, más legible y más fácil de mantener de decir:

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

+1 - ¡Guau! ¡Excelente uso de los decoradores de función! –

+2

Trata de no usar 'eval' si es posible. Algo así debería funcionar: '[getattr (x, campo) para campo en dir (x) if hasattr (getattr (x, campo), 'orden')]' –

+0

Sabía que tenía que haber una mejor manera :) – badp

1

Siempre y cuando usted está interesado sólo en Python 3.x (y de los paréntesis vacíos en su declaración de clase voy supongo que puede ser), entonces, en realidad, hay una manera simple de hacerlo sin decoradores: Python 3 le permite proporcionar su propio diccionario como objeto para usar mientras se define la clase.

El código siguiente es de PEP3115 excepto para el último par de líneas que he añadido a imprimir los métodos con el fin de:

# 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

No es probablemente uno de los métodos más cortos (el nombre de la clase es C):

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

el filtro expresión devuelve todas las funciones de la clase C.

O en una sola línea:

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

Puede ordenar de alguna manera las funciones, por ejemplo, por el orden lexicográfico de sus nombres a poco la expresión más compleja.

Cuestiones relacionadas