В документации для randrange()
говорится:
Аргументы ключевых слов не следует использовать, поскольку они могут быть интерпретированы неожиданным образом. Например,
randrange(start=100)
интерпретируется какrandrange(0, 100, 1)
.
Если подпись random.randrange(start, stop[, step])
, почему randrange(start=100)
не вызывает ошибку, поскольку stop
не передает значение?
Почему randrange(start=100)
интерпретируется как randrange(0, 100, 1)
?
Я не пытаюсь понять выбор дизайна того, кто написал код, а пытаюсь понять, как это вообще возможно. Я думал, что параметрам без значений по умолчанию необходимо передавать аргументы, иначе возникнет ошибка TypeError.
Одиночный параметр, передаваемый в range()
или аналогичные функции, интерпретируется как значение остановки, а не как начало. Это обрабатывается специальным регистром внутри функции, это не то, что можно выразить в списке параметров функции.
Но если предполагается, что единственный параметр должен быть stop=100
, но имеет имя start=100
, не должно ли это вызывать ошибку?
вывод справки: randrange(start, stop=None, step=1) method of random.Random instance Choose a random item from range(stop) or range(start, stop[, step]).
Первый параметр называется start
, независимо от того, передаете ли вы его позиционно или через ключевое слово. Он просто интерпретируется как stop
, если фактический параметр stop
не указан.
@jasonharper, понятно. Чтение исходного кода, указанного в опубликованном ответе, помогло мне это прояснить. Увидев random.randrange(start, stop[, step])
в документации, я подумал, что stop
не имеет значения по умолчанию. Теперь я вижу, что это так. Наверное, я не понимаю, почему в документах не указана настоящая подпись.
@Джо, если бы в документах это было указано как random.randrange(start[, stop, step])
, то как бы ты узнал, какая подпись будет использоваться при вызове randrange(100)
? В этом отношении документация верна, и то, что вы видите в коде, — это реализация, необходимая для поддержки двух подписей.
@trincot, я думаю, это невозможно, потому что Python не разрешает параметры без значений по умолчанию после параметров со значениями по умолчанию. В противном случае я бы сказал, что подпись random.randrange(start=0, stop, step=1)
. Поэтому показаны две «подписи»?
Учитывая, что есть две сигнатуры, я просто удивлен, что «специальный регистр» не использует один позиционный параметр в качестве stop
, а выдает ошибку для (start=100)
. Является ли причина того, что при увеличении скорости не возникает ошибка?
Что касается вашего предложения для random.randrange(start=0, stop, step=1)
: вы могли бы написать так, но эта подпись двусмысленна; например, когда вы вызываете randrange(2, 2)
: это значения для начала/остановки или для остановки/шага?
@trincot, да, я полагаю, это неоднозначно без четко определенного алгоритма анализа аргументов. Я предполагал, что для любого вызова потребуется передать как минимум столько же аргументов, сколько было параметров без значений по умолчанию, и что если их будет больше, они будут переданы в порядке, указанном в сигнатуре, так что, например, `def f(a=0, b, c=2, d, e=4, f):` при вызове с f(6,7,8,9)
будет интерпретироваться как a=6, b=7, d=8, f=9
. Но я знаю, что в Python это невозможно.
Это связано с тем, что код randrange
также должен поддерживать альтернативную подпись :
random.randrange(stop)
Реализация выполняет проверку, использует ли вызов эту подпись или другую:
random.randrange(start, stop[, step])
Это делается с помощью этого кода:
istart = _index(start)
if stop is None:
if istart > 0:
return self._randbelow(istart)
Это имеет смысл, когда вы вызываете randrange(100)
, где это переводится в вызов _randbelow(100)
, что и предполагалось.
Но когда вы вызываете randrange(start=100)
, мы попадаем в тот же поток, и значение start
тоже интерпретируется как stop
.
Моя версия Python показывает
randrange(start, stop=None, step=1, _int=<class 'int'>)
в реализации. Но обратите внимание, что при единственном аргументеstart
фактически становитсяstop
.