Декоратор, который возвращает несколько функций - PullRequest
3 голосов
/ 23 июня 2019

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

# my_module.py


from scipy import signal


@desired_decorator(new_size=(8, 16, 32))
def resample(x, new_size):
    return signal.resample(x, new_size)

Я бы хотел теперь иметь возможность импортировать resample_8, resample_16 и resample_32 из my_module. Я могу написать декоратор и вернуть ему список функций, но как сделать эти функции доступными в пространстве имен модуля?

1 Ответ

3 голосов
/ 23 июня 2019

Из-за того, что вы можете назначить глобальный словарь без использования хитрых хаков, это практически возможно.(хорошая грамматика)

РЕДАКТИРОВАТЬ: K, может быть, это lil немного подлый.Не пытайтесь делать это дома без присмотра Pythonista. martineau

EDIT2: можно получить глобальные переменные вызывающего абонента, используя интроспекцию стека, что позволяет избежать проблемы импорта, но не будет работать при вызове в неглобальном пространстве имен, илирассеять замешательство в 6 месяцев. user2357112

globals() возвращает словарь глобальных переменных.Назначение этого позволяет пользователю импортировать эти функции

functools.partial - отличный способ создания частичных функций.Это в основном делает «половинный» вызов функции.Создание частичной функции заставляет ее запоминать аргументы и аргументы ключевого слова, а вызов этой частичной функции вызывает исходную функцию с аргументами и аргументами ключевого слова.Подробнее об этом здесь .

Вот декоратор, который вы хотите, хотя я бы настоятельно рекомендовал не использовать его.

from functools import partial

def desired_decorator(**kwargs):
    # make sure there's only one keyword argument
    assert len(kwargs) == 1
    # unpack the single keyword and the values
    keyword, values = (*kwargs.items(),)[0]
    # this is the actual decorator that gets called
    def _make_variants(func):
        for value in values:
            # assign to the globals dictionary
            globals()[
                f"{func.__name__}_{value}"
            ] = partial(func, **{keyword: value})
        # keep the original function available
        return func
    return _make_variants

Моя альтернатива - использовать какой Крис сказал, что создание множества функций из декоратора не годится для обслуживания и для ясности.

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

from functools import partial

# assign your function things here
resample_8 = partial(resample, new_size=8)
# repeat for other names
...