-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Materials for Range tutorial #483
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gahjelle Overall, your code looks good to me. I only flagged a few minor edge cases that it would be nice to handle. Let me know what you think. Thanks!
python-range/float_range.py
Outdated
start: int | ||
stop: int | ||
step: int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these attributes be annotated with the float | int
type hint like in the FloatRange
class?
start: int | |
stop: int | |
step: int | |
start: float | int | |
stop: float | int | |
step: float | int |
python-range/float_range.py
Outdated
if any( | ||
self.step > 0 and self.stop <= self.start, | ||
self.step < 0 and self.stop >= self.start, | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any()
expects an iterable. Perhaps you're missing an extra pair of parentheses?
if any( | |
self.step > 0 and self.stop <= self.start, | |
self.step < 0 and self.stop >= self.start, | |
): | |
if any(( | |
self.step > 0 and self.stop <= self.start, | |
self.step < 0 and self.stop >= self.start, | |
)): |
python-range/float_range.py
Outdated
if any( | ||
self.step > 0 and element >= self.stop, | ||
self.step < 0 and element <= self.stop, | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here:
if any( | |
self.step > 0 and element >= self.stop, | |
self.step < 0 and element <= self.stop, | |
): | |
if any(( | |
self.step > 0 and element >= self.stop, | |
self.step < 0 and element <= self.stop, | |
)): |
python-range/float_range.py
Outdated
@dataclass | ||
class FloatRange: | ||
start: float | int | ||
stop: float | int = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is technically float | int | None
.
stop: int | ||
step: int | ||
_num_steps: int = field(default=0, init=False) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The iterator protocol requires that an iterator object implements the .__iter__()
method as well:
def __iter__(self): | |
return self |
Without it, you won't be able to loop over the iterator itself or pass it into a list()
:
>>> for value in _FloatRangeIterator(1, 3, 0.5):
... print(value)
...
1.0
1.5
2.0
2.5
>>> it = _FloatRangeIterator(1, 3, 0.5)
>>> list(it)
[1.0, 1.5, 2.0, 2.5]
python-range/float_range.py
Outdated
self.step > 0 and element >= self.stop, | ||
self.step < 0 and element <= self.stop, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When .step
is equal to zero, the iteration will never stop. The original range()
function rejects zero as the step, so you could perhaps add similar validation in the .__post_init__()
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've emphasized in the docstring that _FloatRangeIterator
is non-public and should only be instantiated through FloatRange
which does the validation. I'll leave the foot-gun for those desperate to use it ...
if self.stop is None: | ||
self.stop = self.start | ||
self.start = 0 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If step is zero, we should raise an error to handle edge cases:
if math.isclose(self.step, 0):
raise ValueError("'step' must not be zero")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is checked by if not isinstance(self.step, float | int) or self.step == 0
below. I'm switching to isclose()
.
Thanks @bzaczynski for the detailed review. I've updated the code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gahjelle Thank you for the updates. They looks good to me 👍
Where to put new files:
my-awesome-article
How to merge your changes: