2014-09-09 5 views
2

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

def func1(a=x): 
    # do stuff 

def func2(b=y): 
    # pass args to func1 without masking func1 defaults 
    return func1(?) 

Вызов func2() должно привести к func1() вызывается без аргументов или, по крайней мере, с его аргументами по умолчанию, какими бы они ни были.

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

def func2(b=y): 
    # this comes close but what if func2(y) is called? 
    if b == y: 
     return func1() 
    else: 
     return func1(b) 
+0

Если значение по умолчанию равно '1', какая разница в make, если вызывающая функция прошла в '1' или оставила ее в покое? –

+0

func2 затем необходимо обновлять при обновлении func1. Если функции написаны разными авторами, это может быть проблематично. – Praxeolitic

+0

Почему? Если я использую 'frobble = func2 (a = 9)', почему мне было бы интересно, чтобы аргумент 'func1()' по умолчанию менял значение с '9' на' 11'? –

ответ

1

Обычный способ определения, является ли параметр кончили является использование None по умолчанию. Маловероятно, что вы будете вызывать функцию с None, поэтому это полезный маркер.

def func2(b=None): 
    if b is None: 
     return func1() 
    else: 
     return func1(b) 
+0

Это хорошее практическое предложение, но если кто-то хочет немного прорвать внутренности, существует ли окончательный способ определить, использовались ли по умолчанию? – Praxeolitic

+0

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

+0

@Blckknght Я думаю, вы можете сделать это, используя '* args' в качестве списка параметров, но я не так хорошо знаком с этим, и я не собираюсь предлагать его в качестве ответа. –

0

экспедиторская Аргументом должно быть сделано с переменным числом аргументов:

def func2(*args, **kwargs): 
    func1(*args, **kwargs) 

Все будет просто работать, хотя самоанализ может немного пострадать.


Если вам необходимо иногда не передать аргумент, вы можете удалить аргумент, когда:

del kwargs["name"] 

Пример:

def print_wrapper(*args, extrabig=False, **kwargs): 
    if extrabig: 
     args = [arg*2 for arg in args] 
     kwargs["sep"] = kwargs.get("sep", " ") * 2 

    print(*args, **kwargs) 

print_wrapper(2, 4, 8, end="!!!\n") 
#>>> 2 4 8!!! 

print_wrapper(2, 4, 8, sep=", ", end="!!!\n") 
#>>> 2, 4, 8!!! 

print_wrapper(2, 4, 8, extrabig=True, end="!!!\n") 
#>>> 4 8 16!!! 

Если вы действительно не хочу этого делать (хотя вы ошибаетесь), вы можете нас e object, чтобы создать уникальный дозор.

# Bad! Won't let you print None 
def optionally_print_one_thing(thing=None): 
    if thing is not None: 
     print(thing) 

# Better 
_no_argument = object() 
def optionally_print_one_thing(thing=_no_argument): 
    if thing is not _no_argument: 
     print(thing) 
+0

Я думаю, что я читаю вопрос по-другому. Я все равно расширю. – Veedrac

+0

Также может быть, что автор func2 не имеет контроля над func1. – Praxeolitic

+0

@Praxeolitic Я не понимаю, почему это имеет значение. – Veedrac

1

Я подозреваю, что правильный способ сделать это, чтобы ваша func2 функция используется значение дозорного как аргумент по умолчанию, так что вы можете узнать его легко. Если вы получите этот дозор, вы можете настроить аргументы, которые вы передадите, на func1, но вы хотите (например, не передавать никаких аргументов). Вы можете использовать распаковку аргументов для обработки переменной числа аргументов (например, 0-1).

Общепринятое дозорное лицо - None, хотя если это может быть значимым значением для вызывающего абонента, вы можете использовать что-то еще (экземпляр object является общим выбором). Вот пример:

def func1(a="default value"): # lets assume we don't know what this default is 
    # do stuff with a 

# later, perhaps in a different module 

_sentinel = object() # our sentinel object 

def func2(b=_sentinel): 
    if b is _sentinel: # test for the sentinel 
     b = "some useful value" 
     a_args =()  # arguments to func1 is an empty tuple 
    else: 
     a_args = (b,) # pack b into a 1-tuple 

    # do stuff with b perhaps 

    func1(*a_args)  # call func1 with appropriate arguments (either b or nothing) 

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

1

Смотрите этот ответ:

https://stackoverflow.com/a/2088101/933416

Там нет никакого способа, чтобы получить информацию, которую вы хотите от внутренностей. Чтобы определить, использовались ли по умолчанию, вам нужно будет повторно реализовать внутреннюю обработку аргументов по умолчанию в пределах функции, т. Е.:

def func2(*args, **kwargs): 
    if len(args) == 0 and "b" not in kwargs: 
     b = y 
     return func1() 
    else: 
     return func1(b) 

Теперь из первой проверки мы гарантируем, что func2() называли в отличие от func2(y) или func2(b=y). Почти в каждом случае уникальный объект-дозорчик достаточно хорош, чтобы не дать по-настоящему гарантировать, как он был вызван, но это можно сделать.

Но судя по тому, что вы сразу же возвращение результат func1, я не вижу никаких причин, почему func2 даже имеет аргументы по умолчанию. При вызове по умолчанию (func2()) y никогда не используется. Так почему это так? Почему бы вам не просто использовать команду define func2(*a, **k) и передать их непосредственно func1?

+0

Предположительно, 'b' использовался в некоторой не показанной части кода перед вызовом' func1'. Также как часть этой «внутренней обработки аргументов по умолчанию» вы должны убедиться, что 'args' не слишком длинный, а' kwargs' не содержит недопустимый аргумент. Для такой простой задачи это становится слишком большим шаблоном. –

0

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

Единственный раз, когда я обнаружил, что необходимо изменить, как func2 вызовов func1 когда func1 является c функцией с Screwy подписью:

def func2(this, that, those=None): 
    if those is None: 
     return func1(this, that) 
    else: 
     return func1(this, that, those) 
Смежные вопросы