Python декоратор для простой рекурсии? В стандартной библиотеке или в другом месте? - PullRequest
6 голосов
/ 16 февраля 2011

Я ищу декоратор Python, который может сделать функцию рекурсивной.Я пишу множество функций, подобных этой:

def xyz(data):
    if not isinstance(data, TypeThatDenotesSingularity):
        return map(xyz, data)
    return singular_xyz(data)

Я полагаю, что где-то должен быть декоратор (в стандартной библиотеке?), Который может уменьшить количество букв:

@recursive(TypeThatDenotesSingularity)
def xyz(data):
    return singular_xyz(data)

Я искал, но, похоже, никуда не денусь.Возможно, мне не хватает какой-то важной терминологии?

Спасибо, что указали мне правильное направление!

Ответы [ 2 ]

3 голосов
/ 16 февраля 2011

Как насчет этого:

def recursive(stop_type):
    def _inner(func):
        def _recursive(data, *args, **kw):
            if not isinstance(data, stop_type):
                return map(_recursive, data)
            return func(data, *args, **kw)
        return _recursive
    return _inner

Объяснение того, как это работает, если используется как @recursive(MySingularType)

  1. рекурсив вызывается во время декорирования функции с аргументом stop_type, установленным в MySingularType
  2. рекурсивное закрытие возвратов _inner
  3. _inner немедленно вызывается с функцией декорирования, также во время компиляции
  4. _inner возвращает замыкание _recursive, которое теперь является новой функцией, которая вызывается при вызове декорированной функции

Теперь, когда вы вызываете свою функцию: _recursive вызывается. Если тип соответствует, вернуть результат функции. В противном случае, сопоставьте другой вызов _recursive, до бесконечности (ну, действительно, пока не будет stackoverflowium)

Примечание Вы можете опустить *args и **kwargs, если декорированная функция всегда всегда будет принимать только одно значение

1 голос
/ 16 февраля 2011

Я не знаю о декораторе, но вы могли бы сделать это с классом, если вам придется переписывать один и тот же шаблон снова и снова.

class Recursive(object):
    def __init__(self, check_type, singular):
        self.check_type = check_type
        self.singular = singular

    def __call__(self, data):
        if not isinstance(data, self.check_type):
            return map(self, data)
        return self.singular(data)
...