0

Is there anyway to run a for loop with a range of over 13 characters? For example:

for i in range (1000000000000):

I know this won't work but is there any way it could?

T. Green
  • 323
  • 10
  • 20

4 Answers4

3

For python 2.7, use xrange (which uses a generator instead of initializing a large list) instead:

for i in xrange(1000000000000):
jh314
  • 27,144
  • 16
  • 62
  • 82
3

Using xrange can also give you Python int too large to convert to C long Error as the number has to fit into a C long. To overcome this use itertools.count to create you own range:

  from itertools import count

def myx_range(start, end):
    return iter(count(start).next, end)

If you wanted to use the same logic with python 3:

from itertools import count

def myx_range(start, end):
    cn = count(start)
    return iter(lambda: next(cn), end)

Or a while loop:

from itertools import count

def myx_range(start, end):
    while start < end:
        yield start
        start += 1

A long is 32bit on windows so you are going to hit the limit using xrange with a number that large.

See what-is-the-bit-size-of-long-on-64-bit-windows

Community
  • 1
  • 1
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • 2
    Good sentinel use of `iter()` – AChampion Oct 14 '15 at 19:13
  • This doesn't seem to work in my program. I have to do a nested loop with the same parameters on each loop and it won't work on the second loop. – T. Green Oct 14 '15 at 19:37
  • @T.Green, how would it not? `for i in myx_range(0, 100000000000)` will work as many times as you want it to – Padraic Cunningham Oct 14 '15 at 19:38
  • How exactly are you using it? – Padraic Cunningham Oct 14 '15 at 19:42
  • 1
    @PadraicCunningham I was using it wrong, I thought the function was the loop, I didn't realise ro had to write the `for i in myx_range(0, 1000000000000)` but know it works. Thanks! :) – T. Green Oct 14 '15 at 19:46
  • @PadraicCunningham: FYI, the first version could simplify to `return iter(count(start).next, end)` and halve the runtime overhead (it moves all the work per iteration to the C layer). Sure, it's not portable to Py3 (where iteration is done with `__next__` instead of `next`), but if you need to work on both Py2 and Py3, I'd suggest doing a version check and only using homegrown code for `myx_range` on Py2, on Py3, you'd just make `myx_range` an alias of `range`. – ShadowRanger Oct 14 '15 at 20:37
  • 1
    @ShadowRanger, True, originally I did not have it in a function so just left the loop. I changed it but kept the lambda in case someone wanted to use a variation of it with python3. – Padraic Cunningham Oct 14 '15 at 21:07
0

If the bounds and step are within the range [-sys.maxsize-1, sys.maxsize), and the total number of elements is <= sys.maxsize, then xrange has you covered.

If not, itertools provides the parts you need to completely reimplement xrange (and efficiently too, pushing all the work to the C layer in CPython) for the purposes of generation (xrange is a real object can be generated over and over and supports a few other features; this only generates, and only once per call):

from itertools import count, islice

def myxrange(stop, *args):
    '''Replacement for xrange to generate ranges of arbitrarily large numbers efficiently
    '''
    start, step = 0, 1  # Defaults when only one argument passed
    if args:
        if len(args) > 2:
            raise TypeError("myxrange expected at most 3 arguments, got {}".format(len(args)))
        start = stop  # When 2+ args passed, stop is really start
        stop, step = (args + (1,))[:2]  # Use step if given, otherwise 1
    # islice slices x items, we need to calculate the number to slice
    # from the bounds given
    numitems = (stop - start + (step - (1 if step > 0 else -1))) // step
    return islice(count(start, step), numitems)

The above is obviously slightly overkill to handle steps other than the default 1; it could be simplified dramatically if step support wasn't needed.

In CPython (the reference interpreter) this should run more efficiently than using Python level code (which requires repeated byte code execution); once initialized, islice and count do all their work at the C layer, which can dramatically improve performance. For example, compared to the while based loop from the other answer, in ipython running on Python 2.7 on my machine:

>>> %timeit -r5 list(xrange(10, 2000))
100000 loops, best of 5: 15.2 μs per loop
>>> %timeit -r5 list(myxrange(10, 2000)) # Version in my answer
10000 loops, best of 5: 24.9 μs per loop
>>> %timeit -r5 list(myxrange2(10, 2000)) # Version using while from Padraig's answer
1000 loops, best of 5: 173 μs per loop

# Padraig's count based version takes 124 μs, though it could be optimized
# down to ~59 μs by changing it to the C layer version (though either
# version breaks if start > stop):
def myxrange(start, stop):
    return iter(count(start).next, end)

Even with the overhead of mimicking xranges non-standard argument prototype, the overhead for the count+islice code is only about 50% over xrange, which ain't half bad given that it actually handles scenarios xrange can't.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
-2

Remember that there is a limit of minumum and maximum value to store in processor register. It means that not all modules can receive big numbers as arguments.

Pingwin Tux
  • 124
  • 9