Обтекание функций генератора в Python - PullRequest
5 голосов
/ 20 июня 2011

Я пишу некоторый код, который пересекает структуру, которая может иметь циклические ссылки.Вместо того, чтобы явно выполнять проверки в начале рекурсивных функций, я подумал, что создам декоратор, который не позволяет вызывать функцию более одного раза с одними и теми же аргументами.

Ниже приведено описаниес.Как написано, это попытается перебрать Nontype и вызвать исключение.Я знаю, что мог бы это исправить, вернув, скажем, пустой список, но я хотел быть более элегантным.Есть ли способ определить из декоратора, является ли декорируемая функция генератором или нет?Таким образом, я мог бы условно повысить StopIteration, если это генератор, или просто вернуть None в противном случае.

previous = set()
def NO_DUPLICATE_CALLS(func):
    def wrapped(*args, **kwargs):
        if args in previous:
            print 'skipping previous call to %s with args %s %s' % (func.func_name, repr(args), repr(kwargs))
            return
        else:
            ret = func(*args, **kwargs)
            previous.add(args)
            return ret
    return wrapped

@NO_DUPLICATE_CALLS
def foo(x):
    for y in x:
        yield y

for f in foo('Hello'):
    print f

for f in foo('Hello'):
    print f

Ответы [ 2 ]

5 голосов
/ 20 июня 2011

Хорошо, проверьте это:

>>> from inspect import isgeneratorfunction
>>> def foo(x):
...    for y in x:
...        yield y
...
>>> isgeneratorfunction(foo)
True

Для этого требуется Python 2.6 или выше.

4 голосов
/ 20 июня 2011

К сожалению, на самом деле не существует хорошего способа узнать, может ли функция возвращать какой-либо тип итерируемого без его вызова, см. этот ответ на другой вопрос для довольно хорошего объяснения некоторых потенциальных проблем.

Однако вы можете обойти это, используя модифицированный декоратор memoize.Обычно запоминание декораторов создает кэш с возвращаемыми значениями для предыдущих параметров, но вместо сохранения полного значения вы можете просто сохранить тип возвращаемого значения.Когда вы сталкиваетесь с параметрами, которые вы уже видели, просто возвращайте новую инициализацию этого типа, что приведет к пустой строке, списку и т. Д.

Вот ссылка на памятку декоратора, чтобы вы начали:
http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize

...