2014-02-23 4 views
0

В пакете я выделил набор функций/переменных, которые вообще работают в классе. Поскольку эти функции не требовали конкретного контекста, они стали методами класса. Они могут использовать некоторые внешние функции, представленные функцией save_c. Но я не могу получить следующий код для работы:Как ссылаться на метод класса в атрибуте класса?

def save_c(v): 
    print("c :" + v) 


class Writer(object): 

    @classmethod 
    def save(cls, t, v): 
     cls.writers[t](v) 


    @classmethod 
    def save_a(cls, v): 
     print("a :" + v) 


    @classmethod 
    def save_b(cls, v): 
     print("b :" + v) 

    writers = [save_a, save_b, save_c] 


if __name__ == "__main__": 
    Writer.save(1, [1, 2, 3]) 

Предыдущие результаты кода в следующее сообщение об ошибке:

TypeError: 'classmethod' object is not callable 

Кто-нибудь знает, если то, что я пытаюсь сделать, это достижимым? Или я обязан использовать регулярные методы и создавать писателя везде, где мне нужно?

ответ

1

Вы также могли бы сделать его работу, добавив класс-оболочку, которая умнее, о том, что называя то, что он имеет дело.

Поскольку вы упомянули в комментарии, что вам нужно будет сделать звонок одному из writers, я обновил свой ответ, чтобы ответить на это, добавив вложенный класс оболочки для инкапсуляции логики вызова различные вызываемые типы в одном месте. Это классический пример использования ООП для применения принципа DRY.

def save_c(v): 
    print("c :" + v) 

class Writer(object): 
    @classmethod 
    def save(cls, t, v): 
     cls.writers[t](cls, v) 

    @classmethod 
    def save_a(cls, v): 
     print("a :" + v) 

    @staticmethod 
    def save_b(v): 
     print("b :" + v) 

    def _wrapper(writer): 
     if isinstance(writer, classmethod): 
      return type('ClassmethodWrapper', (object,), {'__call__': 
         lambda self, cls, v: writer.__func__(cls, str(v))})() 
     elif isinstance(writer, staticmethod): 
      return type('StaticmethodWrapper', (object,), {'__call__': 
         lambda self, cls, v: writer.__func__(str(v))})() 
     else: 
      return type('VanillaWrapper', (object,), {'__call__': 
         lambda self, cls, v: writer(str(v))})() 

    writers = list(map(_wrapper, (save_a, save_b, save_c))) 

if __name__ == "__main__": 
    Writer.save(0, [1, 2, 3]) # -> a :[1, 2, 3] 
    Writer.save(1, [4, 5, 6]) # -> b :[4, 5, 6] 
    Writer.save(2, [7, 8, 9]) # -> c :[7, 8, 9] 
+0

Мне нравится ваш ответ. Но если мне нужно использовать в более чем одном месте трюк 'writers [t], код становится длинным. –

+0

@Guillaume: См. Обновленную версию моего ответа. – martineau

1

Похоже, вы хотели использовать @staticmethod, а не @classmethod.

Для получения дополнительной информации см What is the difference between @staticmethod and @classmethod in Python?

+0

Замена 'classmethod' декораторы с' staticmethod' из них, и 'cls' префиксов с' Writer' из них приводит к очень похожем санкции: 'TypeError: 'STATICMETHOD' объект не callable'. Так что это не так просто, как кажется: P. –

+0

@ GuillaumeLemaître: Никто не сказал, что это все * вы должны были сделать. Это был просто указатель на то, что я думал (и все еще думаю), правильное направление. – NPE

+0

Несмотря на это, вы должны признать, что ваш ответ был не очень полезен, учитывая настоящую проблему здесь, как указывал мой комментарий. Ответ от @martineau имеет смысл. По крайней мере, это мое мнение. –

1

На самом деле, внутренний атрибут writers должен ссылаться на атрибут методов класса __func__. И да, нам нужно использовать staticmethod декораторы вместо classmethod, чтобы соблюдать ту же подпись, что и для внешних вызовов. Следующий код работает хорошо:

def save_c(v): 
    print("c :" + v) 


class Writer(object): 

    @staticmethod 
    def save(t, v): 
     Writer.writers[t](str(v)) 


    @staticmethod 
    def save_a(v): 
     print("a :" + v) 


    @staticmethod 
    def save_b(v): 
     print("b :" + v) 

    writers = [save_a.__func__, save_b.__func__, save_c] 


if __name__ == "__main__": 
    Writer.save(0, [1, 2, 3]) 
    Writer.save(1, [1, 2, 3]) 
    Writer.save(2, [1, 2, 3]) 
Смежные вопросы