использование супер в задаче сельдерея

У меня есть базовый класс, например:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method,
             name='queue_name',
             base=basetask(), bind=True)
    def calculate_price(self):
        super(BMW, self).calculate_price()

Итак, моя проблема с последней строкой кода, она вызывает: TypeError: super(type, obj): obj must be an instance or subtype of type

Я пытался удалить bind=True и немного поиграть с ним, но безрезультатно. Любые идеи, как решить эту проблему?

ОБНОВЛЕНИЕ: где

celery = Celery(...)

Итак, я использую декоратор, например app.task


person smart    schedule 31.12.2016    source источник
comment
Обычно декоратор задач используется с функциями, а не с методами. Я не говорю, что это невозможно, но это редкость. Существует множество ресурсов, посвященных тому, как классифицировать поведение при выполнении задач (например, blog.balthazar- rouberol.com/celery-best-practices), но декоратор задач по-прежнему применяется к простой функции. Возможно, вы могли бы упростить свой дизайн таким образом. Также актуально: stackoverflow.com/questions/9250317 /   -  person FMc    schedule 01.01.2017
comment
@FMc, я читал обе эти темы. Таких случаев как у меня там нет. Мне действительно нужен базовый класс и запуск некоторых методов в дочернем классе в качестве задачи celery. Поэтому мне нужно как-то решить мою проблему, без изменения архитектуры.   -  person smart    schedule 01.01.2017
comment
Да, в этих темах нет случаев, подобных вашему, или в какой-либо документации по Celery, потому что я не думаю, что Celery поддерживает использование декоратора задачи против метода. Вам нужно использовать функцию. В частности, в предоставленной мной ссылке StackOverflow обратите внимание на комментарий от Hamy. Похоже, ваш текущий дизайн просто не будет работать.   -  person FMc    schedule 01.01.2017
comment
@FMc, я немного обновил свой вопрос ... Я использую свой декоратор как app.task в качестве предложенной документации для celery 4.X. Вот почему я могу быть уверен, что он поддерживает на данный момент   -  person smart    schedule 02.01.2017


Ответы (1)


Вы смешиваете два стиля методов: методы класса (@classmethod) и методы экземпляра (def calculate_price(self):).

Я действительно не пробовал это в коде, но как насчет:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method, name='queue_name', base=basetask(), bind=True)
    @classmethod
    def calculate_price(cls, task_self):
        super(BMW, cls).calculate_price()

Таким образом, декоратор @classmethod сначала применяется к def calculate_price(...):, а затем @celery.task применяется к методу класса.

Если вам нужно, чтобы calculate_price() был методом экземпляра, тогда сигнатура может быть def calculate_price(self, task_self):, но вам нужно применить декоратор, когда у вас уже есть экземпляр, например:

my_car = BMW()
celery.task(my_car.calculate_price)

Когда вы обращаетесь к методу с помощью instance<dot>method, вы не получаете написанную вами функцию, вы получаете дескриптор метода, который при вызове позаботится о заполнении первого аргумента (self), оставив вам заполнение остальных аргументов. В данном случае это только аргумент task_self, и об этом позаботится декоратор @celery.task.

В любом случае, я думаю, вам следует отступить и переосмыслить свою проблему более общим образом, вместо того, чтобы выяснять, как связать методы класса/экземпляра с Celery. В общем, задачи Celery должны быть просто функциями, живущими в модуле внутри вашего приложения, которые принимают параметры, которые можно легко сериализовать с помощью JSON.

person Armando Pérez Marqués    schedule 06.03.2017