Pure python range implementationPython implementation of SHA1ECDH implementation in pythonLSB steganography with pure PythonPython implementation for contains pattern in textPython implementation for Setiterative binary_search Python implementationis_subset Python implementationPython Float point range() operator implementationContinuous Range classPython implementation of atoi
Why is it called a stateful and a stateless firewall?
Beauville-Laszlo for schemes
What is the origin of the "being immortal sucks" trope?
Latex matrix formatting
How to generate short fixed length cryptographic hashes?
Tips for remembering the order of parameters for ln?
What is the difference between an engine skirt and an engine nozzle?
How would you translate Evangelii Nuntiandi?
Why would a fighter use the afterburner and air brakes at the same time?
In Bb5 systems against the Sicilian, why does White exchange their b5 bishop without playing a6?
Very lazy puppy
Pure python range implementation
Madrid to London w/ Expired 90/180 days stay as US citizen
Have you ever been issued a passport or national identity card for travel by any other country?
What's the benefit of prohibiting the use of techniques/language constructs that have not been taught?
What is this WWII four-engine plane on skis?
Why are two-stroke engines nearly unheard of in aviation?
What does “We have long ago paid the goblins of Moria,” from The Hobbit mean?
Wouldn't Kreacher have been able to escape even without following an order?
How to give my students a straightedge instead of a ruler
Python web-scraper to download table of transistor counts from Wikipedia
Statistical tests for benchmark comparison
Does household ovens ventilate heat to the outdoors?
Anagrams Question
Pure python range implementation
Python implementation of SHA1ECDH implementation in pythonLSB steganography with pure PythonPython implementation for contains pattern in textPython implementation for Setiterative binary_search Python implementationis_subset Python implementationPython Float point range() operator implementationContinuous Range classPython implementation of atoi
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I implemented class Range
as an equivalent to Python built-in range
for practicing purposes. No features were added. Hope it mimics all aspects of range
behavior, but maybe you can point out something I forgot. Also I tried to make the code efficient, that's why Range
doesn't inherit from collections.abc.Sequence
and doesn't use any of it's not abstract methods. All feedback on how to improve the code is welcome!
pyrange.py
"""
Pure Python implementation of built-in range
"""
import math
import collections.abc
import numbers
def interpret_as_integer(obj):
if hasattr(obj, '__index__'):
return obj.__index__()
raise TypeError(
''' object cannot be interpreted as an integer'.format(
type(obj).__name__
)
)
def adjust_indices(length, start, stop, step):
if step is None:
step = 1
else:
step = interpret_as_integer(step)
if start is None:
start = length - 1 if step < 0 else 0
else:
start = interpret_as_integer(start)
if start < 0:
start += length
if start < 0:
start = -1 if step < 0 else 0
elif start >= length:
start = length - 1 if step < 0 else length
if stop is None:
stop = -1 if step < 0 else length
else:
stop = interpret_as_integer(stop)
if stop < 0:
stop += length
if stop < 0:
stop = -1 if step < 0 else 0
elif stop >= length:
stop = length - 1 if step < 0 else length
return start, stop, step
class Range:
"""
Range(stop) -> Range object
Range(start, stop[, step]) -> Range object
Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step. Range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted! Range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
"""
__slots__ = ('start', 'stop', 'step', '_len')
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = (
interpret_as_integer(obj) for obj in (start, stop, step)
)
if step == 0:
raise ValueError('Range() arg 3 must not be zero')
step_sign = int(math.copysign(1, self.step))
self._len = max(
1 + (self.stop - self.start - step_sign) // self.step, 0
)
def __contains__(self, value):
if isinstance(value, numbers.Integral):
return self._index(value) != -1
return any(n == value for n in self)
def __eq__(self, other):
if not isinstance(other, Range):
return False
if self._len != len(other):
return False
if self._len == 0:
return True
if self.start != other.start:
return False
if self[-1] == other[-1]:
return True
return False
def __getitem__(self, index):
if isinstance(index, slice):
start, stop, step = adjust_indices(
self._len, index.start, index.stop, index.step
)
return Range(
self.start + self.step * start,
self.start + self.step * stop,
self.step * step
)
index = interpret_as_integer(index)
if index < 0:
index += self._len
if not 0 <= index < self._len:
raise IndexError('Range object index out of Range')
return self.start + self.step * index
def __hash__(self):
if self._len == 0:
return id(Range)
return hash((self._len, self.start, self[-1]))
def __iter__(self):
value = self.start
if self.step > 0:
while value < self.stop:
yield value
value += self.step
else:
while value > self.stop:
yield value
value += self.step
def __len__(self):
return self._len
def __repr__(self):
if self.step == 1:
return 'Range(, )'.format(self.start, self.stop)
return 'Range(, , )'.format(self.start, self.stop, self.step)
def __reversed__(self):
return iter(self[::-1])
def _index(self, value):
index_mul_step = value - self.start
if index_mul_step % self.step:
return -1
index = index_mul_step // self.step
if 0 <= index < self._len:
return index
return -1
def count(self, value):
"""
Rangeobject.count(value) -> integer
Return number of occurrences of value.
"""
return sum(1 for n in self if n == value)
def index(self, value, start=0, stop=None):
"""
Rangeobject.index(value, [start, [stop]]) -> integer
Return index of value.
Raise ValueError if the value is not present.
"""
if start < 0:
start = max(self._len + start, 0)
if stop is None:
stop = self._len
if stop < 0:
stop += self._len
if isinstance(value, numbers.Integral):
index = self._index(value)
if start <= index < stop:
return index
raise ValueError(' is not in Range'.format(value))
i = start
n = self.start + self.step * i
while i < stop:
if n == value:
return i
i += 1
n += self.step
raise ValueError(' is not in Range'.format(value))
collections.abc.Sequence.register(Range)
test_pyrange.py
# pylint: disable = too-few-public-methods
import itertools
from pyrange import Range
class Equal:
def __eq__(self, other):
return True
class Indexable:
def __init__(self, n):
self.n = n
def __index__(self):
return self.n
def test_basic():
small_builtin_range = range(10)
small_my_range = Range(10)
equal = Equal()
assert small_builtin_range.count(equal) == small_my_range.count(equal) == 10
assert small_my_range.index(equal) == small_my_range.index(equal) == 0
big_my_range = Range(0, 10 ** 20, 10 ** 5)
assert 10 ** 15 in big_my_range
assert big_my_range[Indexable(10 ** 3)] == 10 ** 8
assert big_my_range[
Indexable(10 ** 3):Indexable(10 ** 6):Indexable(10 ** 2)
] == Range(10 ** 8, 10 ** 11, 10 ** 7)
def test_slicing():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for slice_start, slice_stop, slice_step in itertools.product(
list(range(-3, 3)) + [None], repeat=3
):
if slice_step == 0:
continue
slc = slice(slice_start, slice_stop, slice_step)
builtin_range_slice = builtin_range[slc]
my_range_slice = my_range[slc]
for name in ('start', 'stop', 'step'):
assert (
getattr(builtin_range_slice, name) ==
getattr(my_range_slice, name)
), (start, stop, step, slice_start, slice_stop, slice_step)
def test_eq_and_hash():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for start_2, stop_2, step_2 in itertools.product(
range(-3, 3), repeat=3
):
if step_2 == 0:
continue
builtin_range_2 = range(start_2, stop_2, step_2)
my_range_2 = Range(start_2, stop_2, step_2)
if builtin_range == builtin_range_2:
assert my_range == my_range_2, (
start, stop, step, start_2, stop_2, step_2
)
assert hash(my_range) == hash(my_range_2), (
start, stop, step, start_2, stop_2, step_2
)
python reinventing-the-wheel interval
New contributor
$endgroup$
add a comment
|
$begingroup$
I implemented class Range
as an equivalent to Python built-in range
for practicing purposes. No features were added. Hope it mimics all aspects of range
behavior, but maybe you can point out something I forgot. Also I tried to make the code efficient, that's why Range
doesn't inherit from collections.abc.Sequence
and doesn't use any of it's not abstract methods. All feedback on how to improve the code is welcome!
pyrange.py
"""
Pure Python implementation of built-in range
"""
import math
import collections.abc
import numbers
def interpret_as_integer(obj):
if hasattr(obj, '__index__'):
return obj.__index__()
raise TypeError(
''' object cannot be interpreted as an integer'.format(
type(obj).__name__
)
)
def adjust_indices(length, start, stop, step):
if step is None:
step = 1
else:
step = interpret_as_integer(step)
if start is None:
start = length - 1 if step < 0 else 0
else:
start = interpret_as_integer(start)
if start < 0:
start += length
if start < 0:
start = -1 if step < 0 else 0
elif start >= length:
start = length - 1 if step < 0 else length
if stop is None:
stop = -1 if step < 0 else length
else:
stop = interpret_as_integer(stop)
if stop < 0:
stop += length
if stop < 0:
stop = -1 if step < 0 else 0
elif stop >= length:
stop = length - 1 if step < 0 else length
return start, stop, step
class Range:
"""
Range(stop) -> Range object
Range(start, stop[, step]) -> Range object
Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step. Range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted! Range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
"""
__slots__ = ('start', 'stop', 'step', '_len')
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = (
interpret_as_integer(obj) for obj in (start, stop, step)
)
if step == 0:
raise ValueError('Range() arg 3 must not be zero')
step_sign = int(math.copysign(1, self.step))
self._len = max(
1 + (self.stop - self.start - step_sign) // self.step, 0
)
def __contains__(self, value):
if isinstance(value, numbers.Integral):
return self._index(value) != -1
return any(n == value for n in self)
def __eq__(self, other):
if not isinstance(other, Range):
return False
if self._len != len(other):
return False
if self._len == 0:
return True
if self.start != other.start:
return False
if self[-1] == other[-1]:
return True
return False
def __getitem__(self, index):
if isinstance(index, slice):
start, stop, step = adjust_indices(
self._len, index.start, index.stop, index.step
)
return Range(
self.start + self.step * start,
self.start + self.step * stop,
self.step * step
)
index = interpret_as_integer(index)
if index < 0:
index += self._len
if not 0 <= index < self._len:
raise IndexError('Range object index out of Range')
return self.start + self.step * index
def __hash__(self):
if self._len == 0:
return id(Range)
return hash((self._len, self.start, self[-1]))
def __iter__(self):
value = self.start
if self.step > 0:
while value < self.stop:
yield value
value += self.step
else:
while value > self.stop:
yield value
value += self.step
def __len__(self):
return self._len
def __repr__(self):
if self.step == 1:
return 'Range(, )'.format(self.start, self.stop)
return 'Range(, , )'.format(self.start, self.stop, self.step)
def __reversed__(self):
return iter(self[::-1])
def _index(self, value):
index_mul_step = value - self.start
if index_mul_step % self.step:
return -1
index = index_mul_step // self.step
if 0 <= index < self._len:
return index
return -1
def count(self, value):
"""
Rangeobject.count(value) -> integer
Return number of occurrences of value.
"""
return sum(1 for n in self if n == value)
def index(self, value, start=0, stop=None):
"""
Rangeobject.index(value, [start, [stop]]) -> integer
Return index of value.
Raise ValueError if the value is not present.
"""
if start < 0:
start = max(self._len + start, 0)
if stop is None:
stop = self._len
if stop < 0:
stop += self._len
if isinstance(value, numbers.Integral):
index = self._index(value)
if start <= index < stop:
return index
raise ValueError(' is not in Range'.format(value))
i = start
n = self.start + self.step * i
while i < stop:
if n == value:
return i
i += 1
n += self.step
raise ValueError(' is not in Range'.format(value))
collections.abc.Sequence.register(Range)
test_pyrange.py
# pylint: disable = too-few-public-methods
import itertools
from pyrange import Range
class Equal:
def __eq__(self, other):
return True
class Indexable:
def __init__(self, n):
self.n = n
def __index__(self):
return self.n
def test_basic():
small_builtin_range = range(10)
small_my_range = Range(10)
equal = Equal()
assert small_builtin_range.count(equal) == small_my_range.count(equal) == 10
assert small_my_range.index(equal) == small_my_range.index(equal) == 0
big_my_range = Range(0, 10 ** 20, 10 ** 5)
assert 10 ** 15 in big_my_range
assert big_my_range[Indexable(10 ** 3)] == 10 ** 8
assert big_my_range[
Indexable(10 ** 3):Indexable(10 ** 6):Indexable(10 ** 2)
] == Range(10 ** 8, 10 ** 11, 10 ** 7)
def test_slicing():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for slice_start, slice_stop, slice_step in itertools.product(
list(range(-3, 3)) + [None], repeat=3
):
if slice_step == 0:
continue
slc = slice(slice_start, slice_stop, slice_step)
builtin_range_slice = builtin_range[slc]
my_range_slice = my_range[slc]
for name in ('start', 'stop', 'step'):
assert (
getattr(builtin_range_slice, name) ==
getattr(my_range_slice, name)
), (start, stop, step, slice_start, slice_stop, slice_step)
def test_eq_and_hash():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for start_2, stop_2, step_2 in itertools.product(
range(-3, 3), repeat=3
):
if step_2 == 0:
continue
builtin_range_2 = range(start_2, stop_2, step_2)
my_range_2 = Range(start_2, stop_2, step_2)
if builtin_range == builtin_range_2:
assert my_range == my_range_2, (
start, stop, step, start_2, stop_2, step_2
)
assert hash(my_range) == hash(my_range_2), (
start, stop, step, start_2, stop_2, step_2
)
python reinventing-the-wheel interval
New contributor
$endgroup$
$begingroup$
Your constructor is__init__(start, stop=None, step=1)
. Shouldn'tstart
be optional andstop
positional?range(3)
means[0, 1, 2]
, not[3, 4, 5, ...]
.
$endgroup$
– Jack M
9 hours ago
$begingroup$
@JackM in case ofRange(3)
there are linesif stop is None: start, stop = 0, start
.
$endgroup$
– sanyash
9 hours ago
add a comment
|
$begingroup$
I implemented class Range
as an equivalent to Python built-in range
for practicing purposes. No features were added. Hope it mimics all aspects of range
behavior, but maybe you can point out something I forgot. Also I tried to make the code efficient, that's why Range
doesn't inherit from collections.abc.Sequence
and doesn't use any of it's not abstract methods. All feedback on how to improve the code is welcome!
pyrange.py
"""
Pure Python implementation of built-in range
"""
import math
import collections.abc
import numbers
def interpret_as_integer(obj):
if hasattr(obj, '__index__'):
return obj.__index__()
raise TypeError(
''' object cannot be interpreted as an integer'.format(
type(obj).__name__
)
)
def adjust_indices(length, start, stop, step):
if step is None:
step = 1
else:
step = interpret_as_integer(step)
if start is None:
start = length - 1 if step < 0 else 0
else:
start = interpret_as_integer(start)
if start < 0:
start += length
if start < 0:
start = -1 if step < 0 else 0
elif start >= length:
start = length - 1 if step < 0 else length
if stop is None:
stop = -1 if step < 0 else length
else:
stop = interpret_as_integer(stop)
if stop < 0:
stop += length
if stop < 0:
stop = -1 if step < 0 else 0
elif stop >= length:
stop = length - 1 if step < 0 else length
return start, stop, step
class Range:
"""
Range(stop) -> Range object
Range(start, stop[, step]) -> Range object
Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step. Range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted! Range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
"""
__slots__ = ('start', 'stop', 'step', '_len')
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = (
interpret_as_integer(obj) for obj in (start, stop, step)
)
if step == 0:
raise ValueError('Range() arg 3 must not be zero')
step_sign = int(math.copysign(1, self.step))
self._len = max(
1 + (self.stop - self.start - step_sign) // self.step, 0
)
def __contains__(self, value):
if isinstance(value, numbers.Integral):
return self._index(value) != -1
return any(n == value for n in self)
def __eq__(self, other):
if not isinstance(other, Range):
return False
if self._len != len(other):
return False
if self._len == 0:
return True
if self.start != other.start:
return False
if self[-1] == other[-1]:
return True
return False
def __getitem__(self, index):
if isinstance(index, slice):
start, stop, step = adjust_indices(
self._len, index.start, index.stop, index.step
)
return Range(
self.start + self.step * start,
self.start + self.step * stop,
self.step * step
)
index = interpret_as_integer(index)
if index < 0:
index += self._len
if not 0 <= index < self._len:
raise IndexError('Range object index out of Range')
return self.start + self.step * index
def __hash__(self):
if self._len == 0:
return id(Range)
return hash((self._len, self.start, self[-1]))
def __iter__(self):
value = self.start
if self.step > 0:
while value < self.stop:
yield value
value += self.step
else:
while value > self.stop:
yield value
value += self.step
def __len__(self):
return self._len
def __repr__(self):
if self.step == 1:
return 'Range(, )'.format(self.start, self.stop)
return 'Range(, , )'.format(self.start, self.stop, self.step)
def __reversed__(self):
return iter(self[::-1])
def _index(self, value):
index_mul_step = value - self.start
if index_mul_step % self.step:
return -1
index = index_mul_step // self.step
if 0 <= index < self._len:
return index
return -1
def count(self, value):
"""
Rangeobject.count(value) -> integer
Return number of occurrences of value.
"""
return sum(1 for n in self if n == value)
def index(self, value, start=0, stop=None):
"""
Rangeobject.index(value, [start, [stop]]) -> integer
Return index of value.
Raise ValueError if the value is not present.
"""
if start < 0:
start = max(self._len + start, 0)
if stop is None:
stop = self._len
if stop < 0:
stop += self._len
if isinstance(value, numbers.Integral):
index = self._index(value)
if start <= index < stop:
return index
raise ValueError(' is not in Range'.format(value))
i = start
n = self.start + self.step * i
while i < stop:
if n == value:
return i
i += 1
n += self.step
raise ValueError(' is not in Range'.format(value))
collections.abc.Sequence.register(Range)
test_pyrange.py
# pylint: disable = too-few-public-methods
import itertools
from pyrange import Range
class Equal:
def __eq__(self, other):
return True
class Indexable:
def __init__(self, n):
self.n = n
def __index__(self):
return self.n
def test_basic():
small_builtin_range = range(10)
small_my_range = Range(10)
equal = Equal()
assert small_builtin_range.count(equal) == small_my_range.count(equal) == 10
assert small_my_range.index(equal) == small_my_range.index(equal) == 0
big_my_range = Range(0, 10 ** 20, 10 ** 5)
assert 10 ** 15 in big_my_range
assert big_my_range[Indexable(10 ** 3)] == 10 ** 8
assert big_my_range[
Indexable(10 ** 3):Indexable(10 ** 6):Indexable(10 ** 2)
] == Range(10 ** 8, 10 ** 11, 10 ** 7)
def test_slicing():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for slice_start, slice_stop, slice_step in itertools.product(
list(range(-3, 3)) + [None], repeat=3
):
if slice_step == 0:
continue
slc = slice(slice_start, slice_stop, slice_step)
builtin_range_slice = builtin_range[slc]
my_range_slice = my_range[slc]
for name in ('start', 'stop', 'step'):
assert (
getattr(builtin_range_slice, name) ==
getattr(my_range_slice, name)
), (start, stop, step, slice_start, slice_stop, slice_step)
def test_eq_and_hash():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for start_2, stop_2, step_2 in itertools.product(
range(-3, 3), repeat=3
):
if step_2 == 0:
continue
builtin_range_2 = range(start_2, stop_2, step_2)
my_range_2 = Range(start_2, stop_2, step_2)
if builtin_range == builtin_range_2:
assert my_range == my_range_2, (
start, stop, step, start_2, stop_2, step_2
)
assert hash(my_range) == hash(my_range_2), (
start, stop, step, start_2, stop_2, step_2
)
python reinventing-the-wheel interval
New contributor
$endgroup$
I implemented class Range
as an equivalent to Python built-in range
for practicing purposes. No features were added. Hope it mimics all aspects of range
behavior, but maybe you can point out something I forgot. Also I tried to make the code efficient, that's why Range
doesn't inherit from collections.abc.Sequence
and doesn't use any of it's not abstract methods. All feedback on how to improve the code is welcome!
pyrange.py
"""
Pure Python implementation of built-in range
"""
import math
import collections.abc
import numbers
def interpret_as_integer(obj):
if hasattr(obj, '__index__'):
return obj.__index__()
raise TypeError(
''' object cannot be interpreted as an integer'.format(
type(obj).__name__
)
)
def adjust_indices(length, start, stop, step):
if step is None:
step = 1
else:
step = interpret_as_integer(step)
if start is None:
start = length - 1 if step < 0 else 0
else:
start = interpret_as_integer(start)
if start < 0:
start += length
if start < 0:
start = -1 if step < 0 else 0
elif start >= length:
start = length - 1 if step < 0 else length
if stop is None:
stop = -1 if step < 0 else length
else:
stop = interpret_as_integer(stop)
if stop < 0:
stop += length
if stop < 0:
stop = -1 if step < 0 else 0
elif stop >= length:
stop = length - 1 if step < 0 else length
return start, stop, step
class Range:
"""
Range(stop) -> Range object
Range(start, stop[, step]) -> Range object
Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step. Range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted! Range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
"""
__slots__ = ('start', 'stop', 'step', '_len')
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = (
interpret_as_integer(obj) for obj in (start, stop, step)
)
if step == 0:
raise ValueError('Range() arg 3 must not be zero')
step_sign = int(math.copysign(1, self.step))
self._len = max(
1 + (self.stop - self.start - step_sign) // self.step, 0
)
def __contains__(self, value):
if isinstance(value, numbers.Integral):
return self._index(value) != -1
return any(n == value for n in self)
def __eq__(self, other):
if not isinstance(other, Range):
return False
if self._len != len(other):
return False
if self._len == 0:
return True
if self.start != other.start:
return False
if self[-1] == other[-1]:
return True
return False
def __getitem__(self, index):
if isinstance(index, slice):
start, stop, step = adjust_indices(
self._len, index.start, index.stop, index.step
)
return Range(
self.start + self.step * start,
self.start + self.step * stop,
self.step * step
)
index = interpret_as_integer(index)
if index < 0:
index += self._len
if not 0 <= index < self._len:
raise IndexError('Range object index out of Range')
return self.start + self.step * index
def __hash__(self):
if self._len == 0:
return id(Range)
return hash((self._len, self.start, self[-1]))
def __iter__(self):
value = self.start
if self.step > 0:
while value < self.stop:
yield value
value += self.step
else:
while value > self.stop:
yield value
value += self.step
def __len__(self):
return self._len
def __repr__(self):
if self.step == 1:
return 'Range(, )'.format(self.start, self.stop)
return 'Range(, , )'.format(self.start, self.stop, self.step)
def __reversed__(self):
return iter(self[::-1])
def _index(self, value):
index_mul_step = value - self.start
if index_mul_step % self.step:
return -1
index = index_mul_step // self.step
if 0 <= index < self._len:
return index
return -1
def count(self, value):
"""
Rangeobject.count(value) -> integer
Return number of occurrences of value.
"""
return sum(1 for n in self if n == value)
def index(self, value, start=0, stop=None):
"""
Rangeobject.index(value, [start, [stop]]) -> integer
Return index of value.
Raise ValueError if the value is not present.
"""
if start < 0:
start = max(self._len + start, 0)
if stop is None:
stop = self._len
if stop < 0:
stop += self._len
if isinstance(value, numbers.Integral):
index = self._index(value)
if start <= index < stop:
return index
raise ValueError(' is not in Range'.format(value))
i = start
n = self.start + self.step * i
while i < stop:
if n == value:
return i
i += 1
n += self.step
raise ValueError(' is not in Range'.format(value))
collections.abc.Sequence.register(Range)
test_pyrange.py
# pylint: disable = too-few-public-methods
import itertools
from pyrange import Range
class Equal:
def __eq__(self, other):
return True
class Indexable:
def __init__(self, n):
self.n = n
def __index__(self):
return self.n
def test_basic():
small_builtin_range = range(10)
small_my_range = Range(10)
equal = Equal()
assert small_builtin_range.count(equal) == small_my_range.count(equal) == 10
assert small_my_range.index(equal) == small_my_range.index(equal) == 0
big_my_range = Range(0, 10 ** 20, 10 ** 5)
assert 10 ** 15 in big_my_range
assert big_my_range[Indexable(10 ** 3)] == 10 ** 8
assert big_my_range[
Indexable(10 ** 3):Indexable(10 ** 6):Indexable(10 ** 2)
] == Range(10 ** 8, 10 ** 11, 10 ** 7)
def test_slicing():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for slice_start, slice_stop, slice_step in itertools.product(
list(range(-3, 3)) + [None], repeat=3
):
if slice_step == 0:
continue
slc = slice(slice_start, slice_stop, slice_step)
builtin_range_slice = builtin_range[slc]
my_range_slice = my_range[slc]
for name in ('start', 'stop', 'step'):
assert (
getattr(builtin_range_slice, name) ==
getattr(my_range_slice, name)
), (start, stop, step, slice_start, slice_stop, slice_step)
def test_eq_and_hash():
for start, stop, step in itertools.product(range(-3, 3), repeat=3):
if step == 0:
continue
builtin_range = range(start, stop, step)
my_range = Range(start, stop, step)
for start_2, stop_2, step_2 in itertools.product(
range(-3, 3), repeat=3
):
if step_2 == 0:
continue
builtin_range_2 = range(start_2, stop_2, step_2)
my_range_2 = Range(start_2, stop_2, step_2)
if builtin_range == builtin_range_2:
assert my_range == my_range_2, (
start, stop, step, start_2, stop_2, step_2
)
assert hash(my_range) == hash(my_range_2), (
start, stop, step, start_2, stop_2, step_2
)
python reinventing-the-wheel interval
python reinventing-the-wheel interval
New contributor
New contributor
edited 10 hours ago
dfhwze
11.7k2 gold badges22 silver badges77 bronze badges
11.7k2 gold badges22 silver badges77 bronze badges
New contributor
asked 10 hours ago
sanyashsanyash
1414 bronze badges
1414 bronze badges
New contributor
New contributor
$begingroup$
Your constructor is__init__(start, stop=None, step=1)
. Shouldn'tstart
be optional andstop
positional?range(3)
means[0, 1, 2]
, not[3, 4, 5, ...]
.
$endgroup$
– Jack M
9 hours ago
$begingroup$
@JackM in case ofRange(3)
there are linesif stop is None: start, stop = 0, start
.
$endgroup$
– sanyash
9 hours ago
add a comment
|
$begingroup$
Your constructor is__init__(start, stop=None, step=1)
. Shouldn'tstart
be optional andstop
positional?range(3)
means[0, 1, 2]
, not[3, 4, 5, ...]
.
$endgroup$
– Jack M
9 hours ago
$begingroup$
@JackM in case ofRange(3)
there are linesif stop is None: start, stop = 0, start
.
$endgroup$
– sanyash
9 hours ago
$begingroup$
Your constructor is
__init__(start, stop=None, step=1)
. Shouldn't start
be optional and stop
positional? range(3)
means [0, 1, 2]
, not [3, 4, 5, ...]
.$endgroup$
– Jack M
9 hours ago
$begingroup$
Your constructor is
__init__(start, stop=None, step=1)
. Shouldn't start
be optional and stop
positional? range(3)
means [0, 1, 2]
, not [3, 4, 5, ...]
.$endgroup$
– Jack M
9 hours ago
$begingroup$
@JackM in case of
Range(3)
there are lines if stop is None: start, stop = 0, start
.$endgroup$
– sanyash
9 hours ago
$begingroup$
@JackM in case of
Range(3)
there are lines if stop is None: start, stop = 0, start
.$endgroup$
– sanyash
9 hours ago
add a comment
|
1 Answer
1
active
oldest
votes
$begingroup$
It does not mimic all aspects of range
. The range
object is immutable:
>>> r = range(1,5,2)
>>> r.start
1
>>> r.start = 3
Traceback (most recent call last):
module __main__ line 130
traceback.print_exc()
module <module> line 1
r.start = 3
AttributeError: readonly attribute
>>>
Yours is not. But you might be able to fix that by inheriting from collections.namedtuple
.
$endgroup$
$begingroup$
Good point about immutability. However I don't think that inhertiting fromcollections.namedtuple
is the best idea. Do you know another alternatives?
$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting fromnamedtuple
?
$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logicallyRange
has nothing common withnamedtuple
ortuple
.range_obj[0] == range_obj.start
butrange_obj[1] != range_obj.stop
in many cases andrange_obj[2] != range_obj.step
in many cases.
$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking__setattr__
is the best way.
$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass anamedtuple
and overload the__getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the__setattr__
hack, so you can make yourRange
immutable that way.
$endgroup$
– AJNeufeld
5 hours ago
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
sanyash is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229073%2fpure-python-range-implementation%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
It does not mimic all aspects of range
. The range
object is immutable:
>>> r = range(1,5,2)
>>> r.start
1
>>> r.start = 3
Traceback (most recent call last):
module __main__ line 130
traceback.print_exc()
module <module> line 1
r.start = 3
AttributeError: readonly attribute
>>>
Yours is not. But you might be able to fix that by inheriting from collections.namedtuple
.
$endgroup$
$begingroup$
Good point about immutability. However I don't think that inhertiting fromcollections.namedtuple
is the best idea. Do you know another alternatives?
$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting fromnamedtuple
?
$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logicallyRange
has nothing common withnamedtuple
ortuple
.range_obj[0] == range_obj.start
butrange_obj[1] != range_obj.stop
in many cases andrange_obj[2] != range_obj.step
in many cases.
$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking__setattr__
is the best way.
$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass anamedtuple
and overload the__getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the__setattr__
hack, so you can make yourRange
immutable that way.
$endgroup$
– AJNeufeld
5 hours ago
add a comment
|
$begingroup$
It does not mimic all aspects of range
. The range
object is immutable:
>>> r = range(1,5,2)
>>> r.start
1
>>> r.start = 3
Traceback (most recent call last):
module __main__ line 130
traceback.print_exc()
module <module> line 1
r.start = 3
AttributeError: readonly attribute
>>>
Yours is not. But you might be able to fix that by inheriting from collections.namedtuple
.
$endgroup$
$begingroup$
Good point about immutability. However I don't think that inhertiting fromcollections.namedtuple
is the best idea. Do you know another alternatives?
$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting fromnamedtuple
?
$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logicallyRange
has nothing common withnamedtuple
ortuple
.range_obj[0] == range_obj.start
butrange_obj[1] != range_obj.stop
in many cases andrange_obj[2] != range_obj.step
in many cases.
$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking__setattr__
is the best way.
$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass anamedtuple
and overload the__getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the__setattr__
hack, so you can make yourRange
immutable that way.
$endgroup$
– AJNeufeld
5 hours ago
add a comment
|
$begingroup$
It does not mimic all aspects of range
. The range
object is immutable:
>>> r = range(1,5,2)
>>> r.start
1
>>> r.start = 3
Traceback (most recent call last):
module __main__ line 130
traceback.print_exc()
module <module> line 1
r.start = 3
AttributeError: readonly attribute
>>>
Yours is not. But you might be able to fix that by inheriting from collections.namedtuple
.
$endgroup$
It does not mimic all aspects of range
. The range
object is immutable:
>>> r = range(1,5,2)
>>> r.start
1
>>> r.start = 3
Traceback (most recent call last):
module __main__ line 130
traceback.print_exc()
module <module> line 1
r.start = 3
AttributeError: readonly attribute
>>>
Yours is not. But you might be able to fix that by inheriting from collections.namedtuple
.
answered 6 hours ago
AJNeufeldAJNeufeld
12.1k1 gold badge11 silver badges37 bronze badges
12.1k1 gold badge11 silver badges37 bronze badges
$begingroup$
Good point about immutability. However I don't think that inhertiting fromcollections.namedtuple
is the best idea. Do you know another alternatives?
$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting fromnamedtuple
?
$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logicallyRange
has nothing common withnamedtuple
ortuple
.range_obj[0] == range_obj.start
butrange_obj[1] != range_obj.stop
in many cases andrange_obj[2] != range_obj.step
in many cases.
$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking__setattr__
is the best way.
$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass anamedtuple
and overload the__getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the__setattr__
hack, so you can make yourRange
immutable that way.
$endgroup$
– AJNeufeld
5 hours ago
add a comment
|
$begingroup$
Good point about immutability. However I don't think that inhertiting fromcollections.namedtuple
is the best idea. Do you know another alternatives?
$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting fromnamedtuple
?
$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logicallyRange
has nothing common withnamedtuple
ortuple
.range_obj[0] == range_obj.start
butrange_obj[1] != range_obj.stop
in many cases andrange_obj[2] != range_obj.step
in many cases.
$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking__setattr__
is the best way.
$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass anamedtuple
and overload the__getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the__setattr__
hack, so you can make yourRange
immutable that way.
$endgroup$
– AJNeufeld
5 hours ago
$begingroup$
Good point about immutability. However I don't think that inhertiting from
collections.namedtuple
is the best idea. Do you know another alternatives?$endgroup$
– sanyash
6 hours ago
$begingroup$
Good point about immutability. However I don't think that inhertiting from
collections.namedtuple
is the best idea. Do you know another alternatives?$endgroup$
– sanyash
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting from
namedtuple
?$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
The are hacks to make objects immutable, such as here and here, but why are you opposed to inheriting from
namedtuple
?$endgroup$
– AJNeufeld
6 hours ago
$begingroup$
Because logically
Range
has nothing common with namedtuple
or tuple
. range_obj[0] == range_obj.start
but range_obj[1] != range_obj.stop
in many cases and range_obj[2] != range_obj.step
in many cases.$endgroup$
– sanyash
6 hours ago
$begingroup$
Because logically
Range
has nothing common with namedtuple
or tuple
. range_obj[0] == range_obj.start
but range_obj[1] != range_obj.stop
in many cases and range_obj[2] != range_obj.step
in many cases.$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking
__setattr__
is the best way.$endgroup$
– sanyash
6 hours ago
$begingroup$
As I see, hacking
__setattr__
is the best way.$endgroup$
– sanyash
6 hours ago
$begingroup$
Hmm. It seems I can’t subclass a
namedtuple
and overload the __getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the __setattr__
hack, so you can make your Range
immutable that way.$endgroup$
– AJNeufeld
5 hours ago
$begingroup$
Hmm. It seems I can’t subclass a
namedtuple
and overload the __getitem__
method to a different behaviour. How ... exceptional. Well, you’ve got the __setattr__
hack, so you can make your Range
immutable that way.$endgroup$
– AJNeufeld
5 hours ago
add a comment
|
sanyash is a new contributor. Be nice, and check out our Code of Conduct.
sanyash is a new contributor. Be nice, and check out our Code of Conduct.
sanyash is a new contributor. Be nice, and check out our Code of Conduct.
sanyash is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229073%2fpure-python-range-implementation%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Your constructor is
__init__(start, stop=None, step=1)
. Shouldn'tstart
be optional andstop
positional?range(3)
means[0, 1, 2]
, not[3, 4, 5, ...]
.$endgroup$
– Jack M
9 hours ago
$begingroup$
@JackM in case of
Range(3)
there are linesif stop is None: start, stop = 0, start
.$endgroup$
– sanyash
9 hours ago