Использование частичного с условным аргументом по умолчанию - PullRequest
0 голосов
/ 12 декабря 2018

Я использую partial в библиотечной функции для предоставления ей значения по умолчанию для одного из параметров

library_func = lambda x, y, z : x + y + z

my_func = functools.partial(library_func, z = 5) #default value for one of the variables
# equiv to lambda x, y : x + y + 5

Теперь предположим, что вместо постоянного значения по умолчанию z я хочу, чтобы z былов зависимости от значения yeg, мы ищем z в словаре с ключами, которые имеют разные значения y.

z = {"1":7,"2":8}[str(y)]

# now my_func(x,y) = library_func(x,y,z = f(y))

Возможно ли это?В моем случае использования у меня есть класс, содержащий соединение с базой данных (self.engine)

    self.engine = sqlalchemy.create_engine(connection_string)
    self.read_sql = partial(pd.read_sql, con = self.engine)

, а pd.read_sql имеет сигнатуру типа pd.read_sql(con , name, columns ...)

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

Я думал о

self.read_sql = partial(pd.read_sql, con = self.engine, columns = lambda name: self.name_to_column_dict[name])

, но получаю ошибки (по уважительной причине!)

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Нет, значения по умолчанию для функций partial оцениваются до вызова функции.

В идеале вы можете изменить библиотечную функцию:

def library_func(x, y, z=None):
    if z is None:
        z = {'1': 7, '2': 8}[y]
    return  x + y + z

Но если это не такВозможно, вы можете использовать функцию-оболочку:

def library_func(x, y, z):
    return  x + y + z

def library_func_wrapper(*args):
    return library_func(*args, {'1': 7, '2': 8}[str(args[-1])])

res = library_func_wrapper(6, 2)  # 16
0 голосов
/ 12 декабря 2018

Вместо этого вы можете использовать функцию-обертку:

def my_func(x, y):
    return library_func(x, y, {"1":7,"2":8}[str(y)])

Или, если вы не хотите повторно вводить все аргументы ключевого слова, как вы предложили в комментарии, вы можете использовать inspect.signature для получения подписивашей функции-обертки, а затем привяжите передаваемые аргументы к параметрам, чтобы вы могли получить к ним доступ с помощью ключей dict, независимо от того, переданы ли аргументы как позиционные аргументы или как аргументы ключевых слов:

import inspect

def my_func(*args, **kwargs):
    bound = sig.bind(*args, **kwargs)
    bound.apply_defaults()
    return library_func(**bound.arguments, z={"1":7,"2":8}[str(bound.arguments['y'])])

sig = inspect.signature(my_func)
...