Why does range allow a non-default parameter (stop
) to follow a default parameter (start
)?
Case in point:
>>> r = range(1, 2, 3)
>>> print(r.start, r.stop, r.step)
1 2 3
>>> r = range(10)
>>> print(r.start, r.stop, r.step)
0 10 1
Trying to emulate the signature is an obvious violation:
def my_range(start=0, stop, end=1):
pass
I understand that the fact it is implemented in C
probably allows for behavior that would be a violation in Pythonland.
I'm guessing this was done to make the API more user-friendly but, I didn't find any sources to back it up (The source code doesn't tell much and PEP 457 only states how range
is odd). Does anyone know why this was done?
The error “SyntaxError: non-default argument follows default argument” occurs when you specify a default argument before a non-default argument. To solve this error, ensure that you arrange all arguments in your function definition such that the default arguments come after the non-default arguments.
Only one parameter of a function can be a default parameter. B. Minimum one parameter of a function must be a default parameter.
Default parameter in Javascript The default parameter is a way to set default values for function parameters a value is no passed in (ie. it is undefined ). In a function, Ii a parameter is not provided, then its value becomes undefined . In this case, the default value that we specify is applied by the compiler.
In JavaScript, a parameter has a default value of undefined. It means that if you don't pass the arguments into the function, its parameters will have the default values of undefined .
I think the question is based on a wrong premise:
I understand that the fact it is implemented in C probably allows for behavior that would be a violation in Pythonland.
It's implemented in C but the behaviour isn't a violation in "Pythonland". The signature in the documentation is just incorrect (not actually incorrect, it's an approximation of the "real signature" - that can be easily understood).
For example range
doesn't even support named parameters - but according to the documentation it should:
>>> range(stop=10)
TypeError: range() does not take keyword arguments
So the implementation is more along the lines of:
class range(object):
def __init__(self, *args):
start, step = 0, 1
if len(args) == 1:
stop = args[0]
elif len(args) == 2:
start, stop = args
elif len(args) == 3:
start, stop, step = args
That's valid Python and (roughly) does what range
internally does (the actual implementation (CPython, Python 3.6.1) could be slightly different so don't take that class to seriously).
However a signature like range(*args)
is probably not really helpful for users (especially new users that don't even know what *args
means). Having a documentation that says range
has 2 signatures: range(stop)
and range(start, stop[, step])
may not be (technically) accurate but it "explains" how the signature is interpreted.
As for the why: I don't have any creditable sources but I quickly scanned my code:
I use range(stop)
much more often than range(start, stop)
or range(start, stop, step)
. So the one argument case was probably special and common enough to have a convenience for it. It would be pretty annoying to always write range(0, stop)
all over the place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With