Ok donc j'ai ce code:
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')
Quand j'exécute ceci, je continue à avoir l'erreur:
Exception TypeError: "l'objet 'classmethod' n'est pas appelable"
Je suis incapable de comprendre ce qui ne va pas avec cela et j'apprécierais votre aide.
Vous ne pouvez pas créer de références aux méthodes de classe tant que la classe n'a pas été définie. Vous devrez le sortir de la définition de la classe. Cependant, utiliser une carte globale des fonctions pour décider de ce qui sera exécuté est vraiment délicat. Si vous décrivez ce que vous essayez de faire, nous pourrions probablement suggérer une meilleure solution.
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')
J'ai découvert quelque chose ce soir qui pourrait être utile ici: Nous pouvons décompresser les objets magiques staticmethod
et classmethod
via: getattr(func, '__func__')
Comment ai-je trouvé cette information? En utilisant PyCharm de JetBrains (je ne connais pas d’autres IDE Python), j’ai visualisé le code source pour @staticmethod
et @classmethod
. Les deux classes définissent l'attribut __func__
.
"Le reste est laissé comme un exercice pour le lecteur."
Une méthode de classe enveloppe une fonction donnée avec un objet magique qui n'est pas réellement appelable. Il ne peut être appelé qu'en utilisant la syntaxe ClassName.method(args)
.
Je ne recommanderais pas que vous le fassiez de cette façon, envisagez plutôt de faire quelque chose comme ceci:
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 __== '__main__':
sc = SomeClass()
sc.run('Argumentus-Primus')
Ajoutez self en tant qu'argument pour chaque méthode de la classe.
Également
if _name__='main'
SomeClass.func3('Argumentus-Primus')
devrait ressembler à ceci:
if __name__=='__main__':
SomeClass.func3('Argumentus-Primus')
et ne devrait pas être dans le corps de la classe.
Voici une mauvaise façon de le faire:
def func3(cls,arg1):
global funcList
for func in funcList:
if funcList[func]==True:
eval(f'SomeClass.{func}')(arg1)
Ne fonctionne que si func est le nom de la fonction. Cela étant dit, ne pas utilisez cette méthode, car vous utilisez les entrées de l'utilisateur. Il serait très facile d'injecter du code désagréable dans l'appel. Cela étant dit, cela fonctionne.
Toutes les autres réponses suggèrent d'ajouter du code en dehors de la définition de class SomeClass
. Cela peut aller dans certains cas, mais dans mon cas, c'était très gênant. Je voulais vraiment garder le func_map
dans la classe.
Je suggère l'approche suivante. Utilisez non pas une variable de classe, mais une méthode de classe supplémentaire:
class SomeClass:
# ...
@classmethod
def get_func_map(cls):
return {'func1': cls.func1, 'func2': cls.func2}
@classmethod
def func3(cls, arg1):
# .....
cls.get_func_map()[func_name](arg1)
Bien sûr, vous devez modifier ce code pour qu’un nouveau dictionnaire ne soit pas construit chaque fois que vous appelez la méthode get_func_map
. C'est facile, je ne me suis pas fait de garder l'exemple petit et clair.
Testé sur Python 3.6
Vous devrez peut-être essayer une méthode statique.
@staticmethod
def function():...
Les méthodes statiques ne transmettent pas la classe en tant que premier argument implicite.