classification
Title: In itertools recipes repeatfunc() defines a non-keyword argument as keyword
Type: enhancement Stage:
Components: Documentation Versions: Python 3.3, Python 3.4
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: docs@python, eric.smith, ezio.melotti, py.user, rhettinger
Priority: low Keywords:

Created on 2013-06-27 05:01 by py.user, last changed 2013-09-09 07:34 by rhettinger. This issue is now closed.

Messages (7)
msg191930 - (view) Author: py.user (py.user) * Date: 2013-06-27 05:01
http://docs.python.org/3/library/itertools.html#itertools-recipes
"def repeatfunc(func, times=None, *args):"

>>> repeatfunc(lambda x: x, times=None, 1)
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>>
>>> repeatfunc(lambda x: x, 1, times=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: repeatfunc() got multiple values for argument 'times'
>>>
msg191948 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-06-27 15:05
I'm not sure what you're saying. Given the function definition, the way you're calling it is incorrect, and the error messages explain why.

Are you saying that these ways to call repeatfunc() are documented somewhere that needs fixing? I couldn't find that on the itertools documentation.
msg191949 - (view) Author: py.user (py.user) * Date: 2013-06-27 15:15
it should be: "def repeatfunc(func, times, *args):"
and None for times described in the docstring
msg191950 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-06-27 15:25
I see. You can't call repeatfunc() and specify times with a named argument because of *args. Interesting. I'll let Raymond weigh in.
msg194670 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2013-08-08 13:10
> it should be: "def repeatfunc(func, times, *args):"
> and None for times described in the docstring

This would require you to provide at least two elements, whereas now it's possible to pass just the function (e.g. repeatfunc(random.random)).

The problem with the current signature is that you are "forced" to specify the "times" (positionally) whenever you want to pass args to the function -- even if you want an endless repetition (i.e. times=None).
msg194697 - (view) Author: py.user (py.user) * Date: 2013-08-08 17:19
> This would require you to provide at least two elements
I see
how about "def repeatfunc(func, *args, times=None):" ?


>>> from itertools import starmap, repeat
>>> 
>>> def repeatfunc(func, *args, times=None):
...     """Repeat calls to func with specified arguments.
... 
...     Example:  repeatfunc(random.random)
...     """
...     if times is None:
...         return starmap(func, repeat(args))
...     return starmap(func, repeat(args, times))
... 
>>> def f(*args):
...     print(args)
... 
>>> r = repeatfunc(f, 1, 2)
>>> next(r)
(1, 2)
>>> next(r)
(1, 2)
>>> next(r)
(1, 2)
>>> r = repeatfunc(f, 1, 2, times=1)
>>> next(r)
(1, 2)
>>> next(r)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>
msg197354 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-09-09 07:34
All of the proposed variants have their own issues.  

For example, the keyword-argument variant behaves badly if the user leaves off the keyword:

  >>> list(repeatfunc(ord, 'A', times=3))
  [65, 65, 65]
  >>> list(repeatfunc(ord, 'A', 3))
  Traceback (most recent call last):
    File "<pyshell#12>", line 1, in <module>
      list(repeatfunc(ord, 'A', 3))
  TypeError: ord() takes exactly one argument (2 given)

I prefer to leave the recipe as is.  The primary purpose of the recipe is to illustrate how starmap() and repeat() can be used together.  Will that knowledge, a user can easily cobble together in-line code for either the finite version or the infinite iterable version.
History
Date User Action Args
2013-09-09 07:34:56rhettingersetpriority: normal -> low
status: open -> closed
resolution: rejected
messages: + msg197354
2013-09-01 06:41:01rhettingersetassignee: docs@python -> rhettinger
2013-08-08 17:19:55py.usersetmessages: + msg194697
2013-08-08 13:10:24ezio.melottisetnosy: + ezio.melotti
messages: + msg194670
2013-06-27 15:25:44eric.smithsetstatus: pending -> open

messages: + msg191950
2013-06-27 15:19:03py.usersetstatus: open -> pending
2013-06-27 15:15:49py.usersetstatus: pending -> open

messages: + msg191949
2013-06-27 15:08:20eric.smithsetstatus: open -> pending
2013-06-27 15:05:56eric.smithsetnosy: + eric.smith
messages: + msg191948
2013-06-27 07:35:56ned.deilysetnosy: + rhettinger
2013-06-27 05:01:01py.usercreate