Можно ли создать функцию, которая возвращает значение stati c, сгенерированное при создании, а не при вызове функции? - PullRequest
2 голосов
/ 14 июля 2020

Постановка проблемы:

Как мне создать функцию, которая будет передавать значение, определенное при создании функции, а не при ее вызове?

Фон

Используя altair Я пытаюсь настроить несколько тем, и для создания темы мне нужно «зарегистрировать» it с кодом примерно так:

def black_marks():
    return {
        'config': {
            'mark': {
                'color': 'black',
                'fill': 'black'
            }
        }
    }

# register the custom theme under a chosen name
alt.themes.register('black_marks', black_marks)

# enable the newly registered theme
alt.themes.enable('black_marks')

На этом этапе, поскольку 'black_marks' - это и registerd , и включен , любое будущее использование altair будет включать эти значения по умолчанию.

Обратите внимание, что функция black_marks возвращает dict, и именно функцию необходимо зарегистрировать .

Проблема

У меня есть несколько тем, которые я хотел бы настроить сразу, поэтому я создал al oop с помощью этих конфигураций в моем коде примерно так:

for theme_name, theme_dict in mythemes.items():
    themes.register(theme_name, lambda: theme_dict)

Затем я обнаружил, что темы фактически не зарегистрированы в то время, когда вызывается функция themes.register . Вместо этого он обрабатывается «лениво».

Например, допустим, что ключи темы: ['light', 'dark', 'paper']. Завершив l oop выше, я обнаружил, что все 3 из этих имен тем зарегистрированы (я могу alt.themes.enable('light'), например), но все они указывают на последнюю. , paper. Это происходит потому, что theme_dict в последнем раунде действительно указывает на тему, связанную с paper.

Desire

Я бы хотел иметь возможность каким-то образом «жестко закодировать» то, на что указывает theme_dict, чтобы themes.register указывал на функцию, которая содержит сгенерированный dict на каждом проходе. Но как бы я ни пытался об этом думать, я не могу заставить лямбда-функцию создать функцию, которая «высечена в камне». Вместо этого функция просто вернет все, что было на последней итерации.

Итак, хотя это своего рода проблема altair -specifi c, я чувствую, что решение должно быть общим c одним:

Как мне создать функцию, которая будет передавать значение, которое определяется при создании функции, а не при вызове функции?

Полный пример

Согласно просьбе в комментарии, вот более полный снимок моего кода:

for theme_key, theme_file in THEME_FILES.items(): # THEME_FILES is a dictionary with values containing file paths
    with open(theme_file) as theme_fh:
        raw_theme = toml.load(theme_fh)
    dims = {
        "width": raw_theme.pop("width"),
        "height": raw_theme.pop("height"),
    }
    raw_theme["view"] = dims
    final_theme["config"] = raw_theme
    themes.register(theme_key, lambda: final_theme)

(Извинения за плохие имена переменных ... Я был разочарован проблемы, которые у меня были, и переименование, думая, что проблема была случайной перезаписью глобальных переменных.)

Опять же, для ясности, theme_key правильно зарегистрирован. Если, например, разные ключи были ['light', 'dark', 'paper'], то я могу видеть все 3. Но все три указывают на тему, созданную на последней итерации. В данном случае это тема 'paper'.

Если бы я просто перебрал одну из тем, она работала бы отлично. Так что я почти уверен, что определил проблему.

Ответы [ 2 ]

2 голосов
/ 14 июля 2020

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

def factory(x):
    def theme():
        return x
    return theme

for theme_name, theme_dict in mythemes.items():
    themes.register(theme_name, factory(theme_dict))
0 голосов
/ 14 июля 2020

Если я правильно понимаю проблему, это должно иметь желаемый эффект:

themes.register(theme_name, lambda theme_dict=theme_dict: theme_dict)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...