Issue34169
Created on 2018-07-20 14:11 by chepner, last changed 2022-04-11 14:59 by admin. This issue is now closed.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 8355 | closed | corona10, 2018-07-20 16:47 | |
| Messages (7) | |||
|---|---|---|---|
| msg322010 - (view) | Author: Clint Hepner (chepner) | Date: 2018-07-20 14:11 | |
I expected to be able to pass None as an explicit count to itertools.repeat to get the default behavior of an infinite iterator:
>>> list(islice(repeat(1), 10))
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
>>> list(islice(repeat(1, None), 10))
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
TypeError: 'NoneType' object cannot be interpreted as an integer
|
|||
| msg322029 - (view) | Author: Dong-hee Na (corona10) * ![]() |
Date: 2018-07-20 16:59 | |
IMHO, this issue should be fixed since times=None can be passed, ref: https://docs.python.org/3/library/itertools.html#itertools.repeat This documentation also shows the equivalent python code, From this code, times=None should work but does not work in current implementation. def repeat(object, times=None): # repeat(10, 3) --> 10 10 10 if times is None: while True: yield object else: for i in range(times): yield object I've upload PR with this issue. |
|||
| msg322042 - (view) | Author: Raymond Hettinger (rhettinger) * ![]() |
Date: 2018-07-21 00:17 | |
Clint, why do you think you need this? Dong-hee, the pure python code is listed a rough equivalent, not an exact equivalent. |
|||
| msg322054 - (view) | Author: Dong-hee Na (corona10) * ![]() |
Date: 2018-07-21 00:59 | |
Raymond, when I first read this issue, it seemed very clear that it should not work. However, after reading the documentation I misunderstood that it can be worked because the pseudocode specifies NoneType. IMHO, in that case, we should let users through documentation know that this code is just pseudo-code and that the actual counts parameter should be passed as an integer type. |
|||
| msg322068 - (view) | Author: Raymond Hettinger (rhettinger) * ![]() |
Date: 2018-07-21 03:04 | |
> we should let users through documentation know that this code is just pseudo-code We already modified the docs to specifically say that the provided code is just a rough equivalent. Thanks for the suggestion, but I'm going to decline. There doesn't seem to be a legitimate use case for this. |
|||
| msg322071 - (view) | Author: Terry J. Reedy (terry.reedy) * ![]() |
Date: 2018-07-21 03:31 | |
The 'roughly equivalent' Python code is real code that really runs, and in that sense not pseudocode. itertools is coded in C, which allows optional args with no default. To have optional args when coding in Python, either a default is needed or the argument has to be turned into a residual args tuple of length 0 or 1. In the former case, 'var is None' should be read as being the equivalent of 'var is undefined' in the C code.
In the latter case, the best equivalent, which has its own noise, might be
def repeat(object, *times):
if not times:
while True:
yield object
elif len(times) == 1:
for i in range(times[0]):
yield object
else:
raise TypeError(f'There can be at most 1 times argument, not {len(times)}')
I prefer what we have.
|
|||
| msg322099 - (view) | Author: Clint Hepner (chepner) | Date: 2018-07-21 14:10 | |
This came up in response to https://stackoverflow.com/q/51443795/1126841. I realize the current documentation is informative, not normative, but I think there is a legitimate reason to allow an explicit None argument like the pure Python suggests. Currently, there is no way to trigger the default behavior explicitly, as repeat behaves more like iter (in that the number of arguments has special meaning) than like islice (whose optional arguments behave like regular parameters with default values). For example, these two calls are equivalent: islice(itr, 5) islice(itr, 5, None) For some functions, it makes sense for the number of arguments to be significant. For example, there is no meaningful default value for the second argument to iter(), since the second argument completely changes the semantics of the call. iter({'a': 1, 'b': 2}) # Return an iterator for the argument iter(lambda f: f.read(4), '') # Call a function until it returns '' As an another example, the first argument to map() determines how many additional arguments are needed. map(lambda x: x + 1, [1,2,3]) # yield values form [2,3,4] map(lambda x: x + y, [1,2,3], [1,2,3]) # yield values from [2,4,6] However, with repeat(), it makes sense to think of the second argument as an upper limit that can be either finite or infinite. Lacking an infinite integer value, None makes sense if you read it as "no upper limit" repeat(1) # infinite stream of 1s repeat(1, 10322) # a finite stream repeat(1, None) # proposed: an infinite stream of 1s I prefer the current description of def repeat(object, times=None): over def repeat(object, *times) because it accurately reflects the number of arguments you can pass to repeat. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-04-11 14:59:03 | admin | set | github: 78350 |
| 2018-07-21 14:10:32 | chepner | set | messages: + msg322099 |
| 2018-07-21 03:31:28 | terry.reedy | set | versions:
- Python 3.7 nosy: + terry.reedy messages: + msg322071 type: enhancement |
| 2018-07-21 03:04:04 | rhettinger | set | status: open -> closed resolution: not a bug messages: + msg322068 stage: patch review -> resolved |
| 2018-07-21 00:59:38 | corona10 | set | messages: + msg322054 |
| 2018-07-21 00:17:09 | rhettinger | set | messages: + msg322042 |
| 2018-07-20 19:19:52 | corona10 | set | versions: + Python 3.8 |
| 2018-07-20 16:59:44 | corona10 | set | nosy:
+ corona10 messages: + msg322029 |
| 2018-07-20 16:47:14 | corona10 | set | keywords:
+ patch stage: patch review pull_requests: + pull_request7890 |
| 2018-07-20 15:23:56 | serhiy.storchaka | set | assignee: rhettinger nosy: + rhettinger |
| 2018-07-20 14:11:03 | chepner | create | |
