This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: random.randrange behaviour problems
Type: behavior Stage: needs patch
Components: Documentation Versions: Python 3.1, Python 3.2, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: BreamoreBoy, lukasz.langa, mark.dickinson, rhettinger
Priority: low Keywords:

Created on 2010-07-25 19:18 by lukasz.langa, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (7)
msg111554 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2010-07-25 19:18
Two behaviour problems with random.randrange:

1. Method argument `start` behaves as `stop` if `stop` is not defined:
======================================================================

>>> from random import randrange
>>> help(randrange)
Help on method randrange in module random:

randrange(self, start, stop=None, step=1, int=<class 'int'>, default=None, maxwidth=9007199254740992) method of random.Random instance
    Choose a random item from range(start, stop[, step]).

>>> randrange(10) #start=10
2

Clearly this is because randrange() mimicks the range() interface. Sphinx documentation specifies the behaviour clearly. The problem is, help() can mislead someone in this case.



2. `step` does not work when only `start` (acting as `stop`) specified:
=======================================================================

>>> [randrange(0, 10, step=5) for i in range(10)]
[5, 5, 5, 0, 5, 5, 5, 0, 0, 5]
>>> [randrange(10, step=5) for i in range(10)]
[5, 2, 4, 4, 6, 2, 7, 1, 5, 7]

One would expect the latter to work the same way as the former.



What next
=========

Case 2 is clearly a bug that should be addressed. Raymond, Mark - would a patch for this be accepted for 2.7.x, 3.1.x and 3.2? If so I can provide one.

In Case 1 we can do one of two things (or both):
A. Tweak the docstring to specify the actual behaviour explicitly.
B. Change the function definition to: `randrange(self, limit, *args, **kwargs)`. This is backwards compatible if we'd process `args` and `kwargs` correctly to keep the current interface intact (e.g. `start` would be processed in `kwargs`). This would leave a more predictable help().

Raymond, Mark - I'd say we absolutely do A. Does any of you object about B?
msg111557 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-07-25 21:04
On issue 2: I agree that this is strange behavior, and would be interested to see a patch.  It's not 100% clear to me what the patched code should do, though.  In particular, an example like:

>>> randrange(10, step=5)

that mixes positional and keyword arguments is a bit odd.  It's not clear in this case whether the '10' should be interpreted as a 'start' argument or a 'stop' argument:  on a 'refuse the temptation to guess' basis, I'd say that 'randrange(10, step=5)' should be an error.

More generally, perhaps any randrange call that mixes positional and keyword arguments should raise an exception?

A related behaviour is:

>>> randrange(start=10)
9

This should also be an error, IMO.

Any patch should include comprehensive tests, of course.


On the first issue, yes, it would be good to clarify the docs (see the range docs for how this might be done).

[Łukasz]
> B. Change the function definition to: `randrange(self, limit, *args, 
> **kwargs)`. This is backwards compatible if we'd process `args` and 
> `kwargs` correctly to keep the current interface intact (e.g. `start` 
> would be processed in `kwargs`). This would leave a more predictable 
> help().

Not sure I follow this bit:  is this supposed to be a solution to problem 1 or problem 2?  (Or both?)  I don't really see the benefit of describing randrange this way in the docstring.
msg111558 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2010-07-25 21:31
My suggestions on how the patches should work always assumed that we want 100% backward compatibility and there might exist some crazy code that is actually using positional/keyword argument mixing. If that is no problem for us then I'm all in favor of removing the posibility to mix positional with keyword args in this case.

1B is meant to solve the help() issue. The basic idea is to change the definition so that help() shows a sensible default for all cases. The current one when `start` becomes `stop` is not. The new definition would be:

  def randrange(self, limit, *args, **kwargs)

The docstring would need to have an explanation on the role of `limit` in each sensible case.

Then in the function body there would be some basic code going through what was specified by the user in the args, to assign these values to variables for existing implementation (which is OK).

In effect, there would be 3 major advantages:
- this is backward compatible
- help() would not confuse users
- invocations like randrange(start=30) or randrange(stop=10, step=8) would work properly

If you don't strongly disagree then maybe it will be simpler to just provide a patch for you to review :)
msg111577 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2010-07-25 23:41
I'm happy to improve the docs and docstring a bit to match the description for range().

I don't want to change any of the keyword arguments because it can break code that currently works and has been working for ages.  It's a fact of life that the range() signature is complicated to express in pure Python.  I don't feel any need to reformulate the existing code -- it has been working fine for people for a *very* long time.   Conceptually, it's misleading but in practice people seem to just get it.
msg111580 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2010-07-25 23:48
Raymond, I agree, that is reasonable. Would you like me to send a patch for the docstring or would you rather make the change on your own?
msg111584 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2010-07-26 00:08
You are welcome to suggest wording.  Aim for the shortest explanation that guides people to the right understanding.  Being overly specific often causes more harm than good.  Instead, try to be maximally helpful to someone just learning about randrange() for the first time and is trying to figure out what it does.
msg115739 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2010-09-07 04:48
Added a doc fix to r84576.
Advice is "don't do that" ;-)
History
Date User Action Args
2022-04-11 14:57:04adminsetgithub: 53625
2010-09-07 04:48:28rhettingersetstatus: open -> closed
resolution: fixed
messages: + msg115739
2010-07-26 00:08:56rhettingersetnosy: rhettinger, mark.dickinson, BreamoreBoy, lukasz.langa
components: + Documentation, - Library (Lib)
2010-07-26 00:08:32rhettingersetmessages: + msg111584
2010-07-25 23:48:45lukasz.langasetmessages: + msg111580
2010-07-25 23:41:22rhettingersetpriority: normal -> low
assignee: rhettinger
messages: + msg111577
2010-07-25 21:31:02lukasz.langasetmessages: + msg111558
2010-07-25 21:04:22mark.dickinsonsetmessages: + msg111557
stage: needs patch
2010-07-25 20:14:42mark.dickinsonsetnosy: + mark.dickinson
2010-07-25 19:18:52lukasz.langacreate