The range
function can be used as range(10)
or range(1, 10)
or range(1, 10, 2)
, but at the same time, we cannot use the same function name in a single program more than once. Why is that so?

- 21,433
- 16
- 79
- 117

- 11
-
You can use the same function name multiple times with different parameters, it's called [overloading](https://stackoverflow.com/questions/6434482/python-function-overloading) – Davy M Dec 13 '17 at 16:53
-
function overloading – Ezio Dec 13 '17 at 16:54
-
1Why have you tagged this python3? Any specific version related issue you'd like to discuss? – cs95 Dec 13 '17 at 16:54
-
1if you have two functions named `range`, how do you expect python to know which one you want to use? – Bryan Oakley Dec 13 '17 at 20:13
-
Can you give us an example of what you are trying to do? From your question, what you want to do is very possible in python and you shouldn't be having any issues. – noslenkwah Dec 13 '17 at 20:16
3 Answers
The built-in function range
is a single function that accepts a variable number of inputs.
It is roughly equivalent to:
def myrange(i, j=0, step=1):
if j:
strt, stop = i, j
else:
strt, stop = 0, i
c = strt
while c < stop:
yield c
c += step
which works:
>>> list(myrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(myrange(4, 7))
[4, 5, 6]
>>> list(myrange(1, 20, 2))
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Notice how when we define function parameters, we can use =
to give them default values if they are not inputted when the function is called. This can be done with any function so I think this is what you are looking at.
So to clarify, there are not 3
different range()
functions. There is a single built-in range()
that accepts a variable number or inputs.

- 20,101
- 7
- 33
- 54
You may want to look into using default arguments with your functions. If for example you wanted to create your own implementation of range
, you might write something like the following generator:
#! /usr/bin/env python3
import operator
def main():
array = tuple(custom_range(10))
print(f'custom_range(10) -> {array}')
array = tuple(custom_range(1, 10))
print(f'custom_range(1, 10) -> {array}')
array = tuple(custom_range(1, 10, 2))
print(f'custom_range(1, 10, 2) -> {array}')
array = tuple(custom_range(-10))
print(f'custom_range(-10) -> {array}')
array = tuple(custom_range(-1, -10))
print(f'custom_range(-1, -10) -> {array}')
array = tuple(custom_range(-1, -10, -2))
print(f'custom_range(-1, -10, -2) -> {array}')
def custom_range(start, stop=None, step=None):
none_type = type(None)
if not isinstance(start, int):
raise TypeError('start must be an int')
if not isinstance(stop, (int, none_type)):
raise TypeError('stop must be an int or None')
if not isinstance(step, (int, none_type)):
raise TypeError('step must be an int or None')
if stop is None:
start, stop = 0, start
if step is None:
step = +1 if stop > start else -1 if stop < start else 0
value = start
for condition in operator.lt, operator.gt:
if condition(start, stop):
if not step:
raise ValueError('step may not be zero')
if condition(step, 0):
raise ValueError('step has wrong sign')
while condition(value, stop):
yield value
value += step
if __name__ == '__main__':
main()
One advantage of this implementation is that it is trivial to support the float
data type. However to avoid cumulative addition errors, the innermost loop needs a slight redesign to use multiplication.

- 21,433
- 16
- 79
- 117
we cannot use the same function name in a single program more than once
You absolutely can. But you have to understand that doing so, i.e. declaring a different function with the same name as another will basically overwrite the old one:
def foo():
print('foo!')
foo() # foo!
def foo():
print('bar!')
foo() # bar!
With the later declaration, we are giving the name foo
a new meaning, assigning a different function to it.
So you can absolutely have as many function definitions using the same name. It’s just that at any given time a name in Python can only refer to a single thing. But what that thing is might depend on the context, or scope. For example, if I talk to my friends about “Bob”, I might be talking about a specific person everybody knows. But when I talk about “Bob” at work, my coworkers and I might be referring to a different person. So in that way, the name “Bob” refers to different persons depending on the current scope it is being used in.
And it’s just the same with Python’s names (or variables): A name in a certain refers to a specific object. But in a different scope, the same name might refer to a different object:
def foo():
print('foo!')
def bar():
def foo():
print('bar!')
foo() # this uses the `foo` from the inner scope
foo() # foo!
bar() # bar!
Because of how names work, Python does not allow function overloading which you might know from other programming languages. Objects are only referred to using a name, but not their signature. So the calls foo(x)
and foo(x, y)
will both call the same function object since foo
in both cases refers to the same function object.
So when you do range(10)
, range(1, 10)
, or range(1, 10, 2)
the name range
refers to the same function object, so the same function is called in each case. It’s just that the function is built in a way to support being called with 1, 2, or 3 arguments.
You can do this pretty easily using optional arguments. You can read more about that in the official tutorial on definining functions.

- 369,085
- 72
- 557
- 602