*Memo:
- My post explains the shallow and deep copy of a range.
- My post explains a list (1).
- My post explains a tuple.
- My post explains a set and the set with copy.
- My post explains a frozenset (1).
- My post explains a dictionary (1).
- My post explains an iterator (1).
- My post explains a string.
- My post explains a bytes.
- My post explains a bytearray.
- My post explains enumerate().
- My post explains zip().
A range:
- is the ordered collection of zero or more numbers whose type is
range
:- Ordered means that the order of the numbers in a range is kept so it guarantees that the order is always the same unless someone or something changes it.
- can be huge because it's the special object which always uses low memory not to get
MemoryError
and it's not an iterator. - is immutable(hashable) so it cannot be changed.
- can be iterated with a
for
statement. - can be unpacked with an assignment and
for
statement, function and*
but not with**
. - is
False
if it's empty. - can be checked if a specific element is in the range with
in
keyword. - can be checked if the range is referred to by two variables with
is
keyword. - cannot be enlarged with
*
and a number. - can be created by range().
- can be used with len() to get the length.
- can be read but cannot be changed by indexing or slicing.
- can be continuously used through multiple variables.
- can be shallow-copied (only by slicing) but cannot be deep-copied.
A range can be huge so it doesn't get MemoryError
.
range()
can create a range between [start, stop)
as shown below:
*Memo:
- The 1st argument is
start
orstop
(Required-Type:int
):- It's a start index(inclusive) or stop index(exclusive).
- Don't use
start=
orstop=
.
- The 2nd argument is
stop
(Optional-Type:int
):- It's a stop index(exclusive).
- Don't use
stop=
.
- The 3rd argument is
step
(Optional-Default:1
-Type:int
):- It's the interval of elements.
- It cannot be
0
. - Don't use
step=
.
- Only if one argument is set, the 1st argument is
stop
, creating the range between[0, stop)
.
# Empty range
v = range(0)
v = range(0, 0)
v = range(0, 0, 1)
v = range(5, 5)
v = range(5, 5, 1)
v = range(-10)
v = range(10, -10)
v = range(-10, 10, -3)
v = range(10, -10, 3)
# No error
v = range(5)
v = range(0, 5)
v = range(0, 5, 1)
v = range(-10, 10, 3)
v = range(10, -10, -3)
# No error
for x in range(5): pass
v1, v2, v3 = range(3)
v1, *v2, v3 = range(6)
for v1, v2, v3 in [range(3), range(3, 6)]: pass
for v1, *v2, v3 in [range(6), range(6, 12)]: pass
print(*range(4), *range(4, 6))
print([*range(4), *range(4, 6)])
# No error
v = range(0, 5, 0)
v = range(5) * 3
# Error
A range is the ordered collection of zero or more numbers whose type is range
as shown below:
*Memo:
- A range can be unpacked with
*
. - A range can be read by indexing:
- Indexing can be done with one or more
[index]
.
- Indexing can be done with one or more
v = range(5)
v = range(0, 5)
v = range(0, 5, 1)
print(v)
# range(0, 5)
print(type(v))
# <class 'range'>
print(v.start, v.stop, v.step)
# 0 5 1
print(*v)
print(v[0], v[1], v[2], v[3], v[4])
print(v[-5], v[-4], v[-3], v[-2], v[-1])
# 0 1 2 3 4
v = range(0, 5, 0)
# ValueError: range() arg 3 must not be zero
# Empty range
v1 = range(0)
v2 = range(0, 0)
v3 = range(0, 0, 1)
v4 = range(5, 5)
v5 = range(5, 5, 1)
print(v1, v2, v3, v4, v5)
# range(0, 0) range(0, 0) range(0, 0) range(5, 5) range(5, 5)
print(v[0])
# IndexError: range object index out of range
v = range(-10, 10, 3)
print(v)
# range(-10, 10, 3)
print(*v)
print(v[0], v[1], v[2], v[3], v[4], v[5], v[6])
print(v[-7], v[-6], v[-5], v[-4], v[-3], v[-2], v[-1])
# -10 -7 -4 -1 2 5 8
v = range(10, -10, -3)
print(v)
# range(10, -10, -3)
print(*v)
print(v[0], v[1], v[2], v[3], v[4], v[5], v[6])
print(v[-7], v[-6], v[-5], v[-4], v[-3], v[-2], v[-1])
# 10 7 4 1 -2 -5 -8
v1 = range(-10)
v2 = range(10, -10)
v3 = range(-10, 10, -3)
v4 = range(10, -10, 3)
print(v1, v2, v3, v4)
# range(0, -10) range(10, -10) range(-10, 10, -3) range(10, -10, 3)
print(v1[0])
print(v2[0])
print(v3[0])
print(v4[0])
# IndexError: range object index out of range
A range can be read by slicing as shown below:
*Memo:
- Slicing can be done with one or more
[start:end:step]
:-
start
(Optional-Default:The index of the 1st element
):- It's a start index(inclusive).
-
end
(Optional-Default:The index of the last element + 1
):- It's an end index(exclusive).
-
step
(Optional-Default:1
):- It's the interval of indices.
- It cannot be zero.
- The
[]
with at least one:
is slicing.
-
v1 = range(10)
print(v1)
# range(0, 10)
print(*v1)
# 0 1 2 3 4 5 6 7 8 9
v2 = v1[2:8]
v2 = v1[-8:-2]
print(v2)
# range(2, 8)
print(*v2)
# 2 3 4 5 6 7
v2 = v1[2:8:2]
v2 = v1[-8:-2:2]
print(v2)
# range(2, 8)
print(*v2)
# 2 4 6
A range cannot be changed by indexing or slicing as shown below:
*Memo:
- A del statement can still be used to remove one or more variables themselves.
v = range(5)
v[0] = 10
v[2:5] = [20, 30]
# TypeError: 'range' object does not support item assignment
v = range(5)
del v[0], v[2:5]
# TypeError: 'range' object does not support item deletion
v = range(5)
del v
print(v)
# NameError: name 'v' is not defined
A range can be iterated with a for
statement as shown below:
for x in range(5):
print(x)
# 0
# 1
# 2
# 3
# 4
fruits = ["Apple", "Orange", "Banana", "Kiwi", "Lemon", "Mango"]
for i in range(4):
print(fruits[i])
# Apple
# Orange
# Banana
# kiwi
for i in range(1, 6, 2):
print(fruits[i])
# Orange
# Kiwi
# Mango
for i in range(5, 0, -2):
print(fruits[i])
# Mango
# Kiwi
# Orange
A range can be unpacked with an assignment and for
statement, function and *
but not with **
as shown below:
v1, v2, v3 = range(3)
print(v1, v2, v3)
# 0 1 2
v1, *v2, v3 = range(6)
print(v1, v2, v3) # 0 [1, 2, 3, 4] 5
print(v1, *v2, v3) # 0 1 2 3 4 5
for v1, v2, v3 in [range(3), range(3, 6)]:
print(v1, v2, v3)
# 0 1 2
# 3 4 5
for v1, *v2, v3 in [range(6), range(6, 12)]:
print(v1, v2, v3)
print(v1, *v2, v3)
# 0 [1, 2, 3, 4] 5
# 0 1 2 3 4 5
# 6 [7, 8, 9, 10] 11
# 6 7 8 9 10 11
print(*range(4), *range(4, 6))
# 0 1 2 3 4 5
print([*range(4), *range(4, 6)])
# [0, 1, 2, 3, 4, 5]
def func(p1='a', p2='b', p3='c', p4='d', p5='e', p6='f'):
print(p1, p2, p3, p4, p5, p6)
func()
# a b c d e f
func(*range(4), *range(4, 6))
# 0 1 2 3 4 5
def func(p1='a', p2='b', *args):
print(p1, p2, args)
print(p1, p2, *args)
print(p1, p2, ['A', 'B', *args, 'C', 'D'])
func()
# a b ()
# a b Nothing
# a b ['A', 'B', 'C', 'D']
func(*range(4), *range(4, 6))
# 0 1 (2, 3, 4, 5)
# 0 1 2 3 4 5
# 0 1 ['A', 'B', 2, 3, 4, 5, 'C', 'D']
An empty range is False
as shown below:
print(bool(range(0))) # Empty range
# False
A range can be checked if a specific element is in the range with in
keyword as shown below:
v = range(4)
print(*v)
# 0 1 2 3
print(2 in v)
# True
print(4 in v)
# False
A range cannot be enlarged with *
and a number as shown below:
v = range(5) * 3
# TypeError: unsupported operand type(s) for *: 'range' and 'int'
A range can be used with len()
to get the length as shown below:
v = range(5)
print(*v)
# 0 1 2 3 4
print(len(v))
# 5
A range can be continuously used through multiple variables as shown below:
v1 = v2 = v3 = range(5) # Equivalent
# v1 = range(5)
# v2 = v1
# v3 = v2
print(v1, *v1) # range(0, 5) 0 1 2 3 4
print(v2, *v2) # range(0, 5) 0 1 2 3 4
print(v3, *v3) # range(0, 5) 0 1 2 3 4
A range can be shallow-copied (only by slicing) but cannot deep-copied as shown below:
<Shallow copy>:
*Memo:
-
v1
andv2
refer to different ranges (only by slicing) and each same element. -
is
keyword can check ifv1
andv2
refer to the same range and/or each same element. - Slicing can shallow-copy the range.
- copy.copy() cannot shallow-copy a range.
v1 = range(5)
v2 = v1[:]
print(v1, *v1) # range(0, 5) 0 1 2 3 4
print(v2, *v2) # range(0, 5) 0 1 2 3 4
print(v1 is v2, v1[2] is v2[2])
# False True
import copy
v1 = range(5)
v2 = copy.copy(v1)
print(v1, *v1) # range(0, 5) 0 1 2 3 4
print(v2, *v2) # range(0, 5) 0 1 2 3 4
print(v1 is v2, v1[2] is v2[2])
# True True
<Deep copy>:
*Memo:
-
v1
andv2
refer to the same range and each same element. - copy.deepcopy() cannot deep-copy and even shallow-copy a range.
import copy
v1 = range(5)
v2 = copy.deepcopy(v1)
print(v1, *v1) # range(0, 5) 0 1 2 3 4
print(v2, *v2) # range(0, 5) 0 1 2 3 4
print(v1 is v2, v1[2] is v2[2])
# True True
index() can get the index of the element matched to value
from the range as shown below:
*Memo:
- The 1st argument is
value
(Required-Type:Any). - Error occurs if
value
doesn't exist.
v = range(5, 10)
print(*v)
# 5 6 7 8 9
print(v.index(7)) # 2
print(v.index(10)) # ValueError: 10 is not in range
count() can count the elements matched to value
in the range as shown below:
*Memo:
- The 1st argument is
value
(Required-Type:Any):- Don't use
value=
.
- Don't use
v = range(5, 10)
print(*v)
# 5 6 7 8 9
print(v.count(7)) # 1
print(v.count(10)) # 0
sorted() can convert a range to a list, then sort the list as shown below:
*Memo:
- The 1st argument is
iterable
(Required-Type:Iterable):- Don't use
iterable=
.
- Don't use
- The 2nd argument is
key
(Optional-Default:None
-Type:Callable or NoneType). - The 3rd argument is
reverse
(Optional-Default:False
-Type:bool
) to reverse the list. -
sorted()
creates a copy:- Be careful,
sorted()
does shallow copy instead of deep copy as my issue.
- Be careful,
v = range(-3, 3)
print(*v)
# -3 -2 -1 0 1 2
print(sorted(v))
print(sorted(v, key=None, reverse=False))
# [-3, -2, -1, 0, 1, 2]
print(sorted(v, reverse=True))
# [2, 1, 0, -1, -2, -3]
print(sorted(v, key=abs))
# [0, -1, 1, -2, 2, -3]
print(sorted(v, key=abs, reverse=True))
# [-3, -2, 2, -1, 1, 0]
reversed() can return the iterator which has the reversed elements of a range as shown below:
*Memo:
- The 1st argument is
seq
(Required-Type:Sequence):- Don't use
seq=
.
- Don't use
v = range(5)
print(*v)
# 0 1 2 3 4
print(reversed(v))
# <range_iterator object at 0x0000023D03BF5030>
print(*reversed(v))
# 4 3 2 1 0
Top comments (0)