объект 'classmethod' не вызывается
Итак, у меня есть такой код:
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')
Когда я запускаю это, я продолжаю получать ошибку:
Exception TypeError: "'classmethod' object is not callable"Я не могу понять, что в этом плохого, и был бы признателен вам за помощь.
6 ответов:
Вы не можете создавать ссылки на classmethods, пока класс не определен. Вам придется удалить его из определения класса. Однако использование глобальной карты функций для определения того, что будет запущено, действительно неудобно. Если бы вы описали, что вы пытаетесь сделать с этим, мы, вероятно, могли бы предложить лучшее решение.
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')
Сегодня вечером я обнаружил кое-что, что будет полезно здесь: мы можем развернуть магию
staticmethod
иclassmethod
объекты через:getattr(func, '__func__')
Как я нашел эту информацию? Используя PyCharm JetBrains (я не знаю о других Python IDEs), я просмотрел исходный код для
@staticmethod
и@classmethod
. Оба класса определяют атрибут__func__
."остальное оставлено как упражнение для читателя."
Метод classmethod обертывает данную функцию магическим объектом, который на самом деле не может быть вызван. Его можно вызвать только с помощью синтаксиса
ClassName.method(args)
.Я бы не рекомендовал вам делать это таким образом, подумайте о том, чтобы сделать что-то вроде этого:
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')
Добавьтеself в качестве аргумента для каждого метода в классе.
Также
if _name__='main' SomeClass.func3('Argumentus-Primus')
Должно выглядеть так:
if __name__=='__main__': SomeClass.func3('Argumentus-Primus')
И не должны находиться в теле класса.
Возможно, вам потребуется попробовать статический метод.
@staticmethod def function():...
Статические методы не передают класс в качестве неявного первого аргумента.
Все остальные ответы предполагают добавление некоторого кода вне определения
class SomeClass
. В некоторых случаях это может быть нормально, но в моем случае это было очень неудобно. Я действительно хотел сохранитьfunc_map
внутри класса.Я предлагаю следующий подход. Используйте не переменную класса, А еще один classmethod:
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)
Конечно, вы должны изменить этот код так, чтобы новый словарь не создавался каждый раз, когда вы вызываете метод
get_func_map
. Это легко, я не делал себе этого, чтобы держать пример маленьким и четкий.Протестировано на python 3.6