0

When I'm reading xrange reference, it says like this..

Objects of type xrange are similar to buffers in that there is no specific syntax to create them, but they are created using the xrange() function. They don’t support slicing, concatenation or repetition, and using in, not in, min() or max() on them is inefficient.

However, as long as I have ever seen, all the xrange() that I have used is with in. Like for x in xrange(10): do somethings..

So why it says this way is inefficient? So what is supposed to be the right way to use xrange?

vaultah
  • 44,105
  • 12
  • 114
  • 143
Elona Mishmika
  • 480
  • 2
  • 5
  • 21
  • 3
    **`for`** `x in xrange(10):` (iterating over) is not quite the same as **`if`** `x in xrange(10):` (membership testing)... – jonrsharpe Nov 04 '15 at 14:56
  • It does not say that way is inefficient. It says several methods were not implemented on the internal object instantiated by `xrange` for various performance reasons, and that others may work but should not be preferred. – Two-Bit Alchemist Nov 04 '15 at 15:15

2 Answers2

1

Quoting Perfomance Tips:

xrange is a generator object, basically equivalent to the following Python 2.3 code:

def xrange(start, stop=None, step=1):
    if stop is None:
        stop = start
        start = 0
    else:
        stop = int(stop)
    start = int(start)
    step = int(step)

    while start < stop:
        yield start
        start += step

Except that it is implemented in pure C.

They say that in is inefficient on xrange objects because in tries to iterate over object if the __contains__ approach failed. From Membership test details:

For classes which do not define __contains__() but do define __iter__(), x in y is true if some value z with x == z is produced while iterating over y.

xrange does not implement __contains__ and in order to "find" element N in xrange(N + 1) in operator has to perform N iterations so

N in xrange(N + 1)

is logically equivalent to

for n in xrange(N + 1):
    if n == N:
        break

and it's not efficient.

not in is inefficient because in is inefficient.

Note that performance of in operator for containment tests doesn't affect the performance of the for loop. These are 2 different things.

In fact, the "in" in the grammar rule for the for loop (shown below)

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

is fixed and is not an operator.

vaultah
  • 44,105
  • 12
  • 114
  • 143
0

No, what they've actually meant is

>>> 5 in xrange(0, 10)
True

which is a test for "contains". It is inefficient since it has to travel through all elements in the worst case.

It is not about for loop which is correct and efficient. I suppose that the doc is a bit misleading.

freakish
  • 54,167
  • 9
  • 132
  • 169
  • The documentation is not misleading unless you're doing something like mixing up the performance of `in` within a loop as opposed to a `__contains__` test, like OP is apparently doing. These points of confusion are adequately addressed by other sections of the documentation. Someone who understands all the terms in the sentence properly would have no problem figuring out what it meant. – Two-Bit Alchemist Nov 04 '15 at 15:18
  • @Two-BitAlchemist `The documentation is not misleading` False. There is at least one person confused by it. I know that you would like all people to understand everything but then again SO would lose its purpose, wouldn't it? – freakish Nov 04 '15 at 15:21