2010-11-09 3 views
14

В Python я понимаю, что аргументы по умолчанию приходят в конце и что аргументы, отличные от значения по умолчанию, не могут следовать аргументу по умолчанию. Это нормально. Как, например,:Порядок аргументов по умолчанию и не по умолчанию

>>> def foo(x=0, y): 
     return x, y 
SyntaxError: non-default argument follows default argument 

Это нормально, как ожидалось.

Однако, как насчет того, что первый аргумент должен быть по умолчанию? Как, например, как видно из приведенного выше кода, x должен быть первым аргументом и должен иметь значение по умолчанию 0.

Возможно ли это сделать? Я спрашиваю, потому что даже в функции range, я предполагаю, что это что-то вроде этого:

def range(start=0, end): 
    pass 

Итак, как это делается, и если это не представляется возможным, как это реализуется range? Обратите внимание, что я настаиваю на том, чтобы первый аргумент был по умолчанию, вот и вся цель. В качестве примера я использую range, потому что он идеально подходит для моей проблемы. Конечно, можно было бы реализовать range как def range(end, start=0), но это не главное.

ответ

9

Ну, range есть C код, который может сделать это немного лучше. В любом случае, вы можете сделать это:

def range(start, stop=None): 
    if stop is None: # only one arg, treat stop as start ... 
     stop = start 
     start = 0 
    ... 

и соответствующим образом документировать функцию.

+1

Почти идентичный моему ответу, но яснее и на пять минут раньше. Итак, +1. –

+0

Можете добавить аргумент 'step' для согласованности со встроенным. –

+0

+1. Это идеально. Я чувствую себя глупо, не думая об этом. – user225312

1

Вы можете обрабатывать Исключениями себя, если вы действительно хотите, чтобы

def Range(start=0, end=None): 
    if end is None: 
     raise AttributeError("end value not specified") 
    pass 
2

Не применяется range. Вы можете использовать *args или **args и обрабатывать кортеж или диктофон, как хотите. Например:

 
def f(*args): 
    if len(args) == 1: 
    print "assuming the first is default" 
    elif len(args) == 2: 
    print "two arguments were passed" 
    else: 
    print "Complaining" 

2

Есть пара подходов. Первым было бы переключить аргументы в функции, если некоторые из аргументов «None». Это будет так.

def range1(value, end=None): 
    if end == None: 
     end = value 
     value = 0 
    return _generate_range_values(value, end) 

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

def range2(*args): 
    if len(args) == 1: 
     start = 0 
     end = int(args[0]) 
    elif len(args) == 2: 
     start = int(args[0]) 
     end = int(args[1]) 
    return _generate_range_values(start, end) 

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

def range3(end, start=0): 
    return _generate_range_values(start, end) 

Затем пользователи назвали бы его с именем стартового аргумента, когда они хотели что-то, кроме 0. (Хотя названный аргумент не требуется, она сохраняет код ясный.

for i in range3(55, start=12) 
+0

+1 Даже если я не понимаю, почему вы почувствовали необходимость использовать 'int()' on' args [x] 'в' range2() ', но не в других. Это необязательно (хотя это позволяет этой версии принимать аргументы с плавающей запятой и строкой, такие как «3.14» и «42»). – martineau

+0

Оглядываясь назад, я не уверен, почему я использовал int() в одном из примеров, а не в других. Функция builtin range() вызовет ошибку, если она получит что-либо помимо целых аргументов. –

1

Я не» т есть код диапазона, но я уверен, он выполняет такую ​​хитрость:

def range(start, stop=None, step=1): 
    if stop is None: 
     start, stop = 0, start 
    ... 

редактировать: код исправлен на комментарий Мартино.

Смежные вопросы