2012-06-15 7 views
19

Ok, así que tengo este código:objeto 'classmethod' no es exigible

class SomeClass: 
    @classmethod 
    def func1(cls,arg1): 
     #---Do Something--- 
    @classmethod 
    def func2(cls,arg1): 
     #---Do Something--- 

    # A 'function map' that has function name as its keys and the above function 
    # objects as values 
    func_map={'func1':func1,'func2':func2} 

    @classmethod 
    def func3(cls,arg1): 
     # following is a dict(created by reading a config file) that 
     # contains func names as keys and boolean as values that tells 
     # the program whether or not to run that function 
     global funcList 
     for func in funcList: 
      if funcList[func]==True: 
       cls.func_map[func](arg1)  #TROUBLING PART!!! 

    if _name__='main' 
     SomeClass.func3('Argumentus-Primus') 

Cuando ejecuto esto me siguen dando el error:

 
Exception TypeError: "'classmethod' object is not callable" 

no soy capaz de averiguar qué es malo esto y agradecería su ayuda.

+0

Lo sentimos por no agregar la descripción del error. Editó la respuesta (y eso es todo lo que sé sobre este error). Y si tuviera la respuesta al problema, ¿por qué iba a publicar esta pregunta? : S Busqué este error y encontré que las personas estaban recibiendo estos errores ya que no estaban usando el código correctamente, p. en un hilo, un tipo estaba accediendo a un elemento de un diccionario como 'someDict (key)' y estaba obteniendo un error similar ... pero creo que estoy haciendo una llamada a una función (que debería ser invocable, ¿no?). Corrígeme si estoy equivocado .. – user1126425

+0

Cuando aparezca un error, copie y pegue todo el seguimiento de la pila. Te dirá cosas útiles como en qué línea ocurre el error. –

+0

Lattye, 'Exception TypeError:" el objeto 'classmethod' no se puede llamar "en 'pyadecg.__wrap_py_func 'ignorado' esto es todo lo que puedo ver en la pila de registros .. Gracias por tu ayuda – user1126425

Respuesta

12

No puede crear referencias a classmethods hasta que se haya definido la clase. Tendrás que moverlo fuera de la definición de la clase. Sin embargo, usar un mapa de función global para decidir qué se ejecuta es realmente incómodo. Si describió lo que está tratando de hacer con esto, probablemente podríamos sugerir una mejor solución.

class SomeClass(object): 
    @classmethod 
    def func1(cls, arg1): 
     print("Called func1({})".format(arg1)) 

    @classmethod 
    def func2(cls, arg1): 
     print("Call func2({})".format(arg1)) 

    @classmethod 
    def func3(cls, arg1): 
     for fnName,do in funcList.iteritems(): 
      if do: 
       try: 
        cls.func_map[fnName](arg1) 
       except KeyError: 
        print("Don't know function '{}'".format(fnName)) 

# can't create function map until class has been created 
SomeClass.func_map = { 
    'func1': SomeClass.func1, 
    'func2': SomeClass.func2 
} 

if __name__=='__main__': 
    funcList = {'func1':True, 'func2':False} 
    SomeClass.func3('Argumentus-Primus') 
+2

Gracias por la respuesta Hugh. 1. Esto es realmente confuso para mí. ¿Por qué Python no me detiene justo en ese punto cuando los he refrendado en dict? Solo se quejaba cuando intentaba llamarlo. 2. Este funcList global se creó leyendo un archivo de configuración (la configuración de lectura se realiza en un módulo diferente), así que no se me ocurrió otra manera ... 3. Estoy tratando de obtener una configuración de entrada archivo del usuario que le diría al programa qué funciones ejecutar y al hacerlo, desea mantener una separación clara entre las diferentes partes del código (para hacerlo extensible fácilmente) – user1126425

0

Agregar self como argumento para cada método dentro de la clase.

también

if _name__='main' 
    SomeClass.func3('Argumentus-Primus') 

debería tener este aspecto:

if __name__=='__main__': 
    SomeClass.func3('Argumentus-Primus') 

y no debe ser dentro del cuerpo de la clase.

+0

estos son todos los métodos de clase, no los métodos de instancia. – user1126425

+0

Veo. ¿Por qué no utilizas la declaración de cambio en lugar de un mapa? O puede usar getattr para llamar al método. Eso es si lo hiciste un método de instancia. – ulu5

+0

Estaba tratando de ser elegante en mi código ... y escribirlo para que se pueda extender fácilmente :) No quiero usarlo como métodos de instancia ... porque hace cambios a ciertos recursos que se usan por otros módulos que necesitan verlos de manera consistente. – user1126425

2

Una classmethod envuelve una función dada con un objeto mágico que de hecho no es invocable. Solo se puede llamar usando la sintaxis ClassName.method(args).

No recomendaría que lo haces de esta manera, pensar en hacer algo como esto en su lugar:

func_list = { 
    'func1': True, 
    'func2': False 
} 

class SomeClass(object): 
    def do_func1(self, arg1): 
     print("func1", arg1) 

    def do_func2(self, arg1): 
     print("func2", arg1) 

    def run(self, arg1): 
     for name, enabled in func_list.items(): 
      if enabled: 
       the_method = getattr(self, 'do_' + name) 
       the_method(arg1) 


if __name__ == '__main__': 
    sc = SomeClass() 
    sc.run('Argumentus-Primus') 
+0

Gracias por la respuesta Antti. ¿Estás diciendo que un método de clase no se puede llamar? En mi caso, podría llamar al func3 simplemente usando SomeClass.func3 (arg1), pero el problema parecía ser llamar con otras funciones. Además, necesitaba classmethods para poder hacerlo sin instanciar esta clase en otros módulos (que es una especie de limitación de mi código). – user1126425

+0

¿Y por qué no instanciar? Si nunca crea una instancia de la clase, no necesita una clase. Ni siquiera classmethods ... –

+0

Hmm ... Creo que tienes razón. Estaba siguiendo las convenciones de Java ... De todos modos, me presentó este problema y quiero averiguar por qué no puedo hacerlo de esta manera. – user1126425

0

Es posible que deba probar con un método estático.

@staticmethod 
def function():... 

Los métodos estáticos no pasan la clase como un primer argumento implícito.

+1

Interesante, pero solo lleva a 'TypeError: 'staticmethod' objeto no es invocable' en su lugar. – starfry

9

he descubierto algo esta noche que será útil aquí: Podemos desenvolver mágicos staticmethod y classmethod objetos a través de: getattr(func, '__func__')

¿Cómo puedo encontrar esta información? Usando PyCharm de JetBrains (no sé sobre otros IDEs de Python), vi el código fuente para @staticmethod y @classmethod. Ambas clases definen el atributo __func__.

"El resto queda como ejercicio para el lector".

+2

Esos son tanques creados para pycharm, de modo que la finalización del código y la introspección funcionan. En realidad, esos decoradores son builtins escritos en C –

Cuestiones relacionadas