杰瑞科技汇

Python中range与xrange到底有啥区别?

Of course! This is a classic and very important topic in Python, especially for those who have worked with both Python 2 and Python 3.

Python中range与xrange到底有啥区别?-图1
(图片来源网络,侵删)

Let's break down range and its predecessor xrange in detail.


Executive Summary (TL;DR)

  • xrange was a function in Python 2 that generated numbers on-the-fly (lazily). It was very memory-efficient for large ranges but was removed in Python 3.
  • range is the function in Python 3. It behaves like the old xrange (it's memory-efficient and lazy). The old range from Python 2, which created a full list in memory, was removed.
  • Key Takeaway: In modern Python (3.x), you only need to use range(). It is fast and memory-efficient for all cases.

The Old Days: Python 2

In Python 2, you had two functions to generate sequences of numbers: range() and xrange(). They behaved very differently.

range() in Python 2

The range() function in Python 2 generated a complete list of numbers and stored it in your computer's memory.

Example:

Python中range与xrange到底有啥区别?-图2
(图片来源网络,侵删)
# In Python 2
my_range = range(1000000)
# This creates a list with 1,000,000 integer objects in memory.
# If you have limited memory, this could crash your program.
print(type(my_range))  # <type 'list'>
print(len(my_range))   # 1000000

Pros:

  • You could iterate over it multiple times without re-generating it.
  • You could slice it (e.g., my_range[500:1000]).

Cons:

  • Extremely memory-intensive for large numbers. Creating range(1000000000) would try to allocate a list with a billion integers, which is impossible on most machines.

xrange() in Python 2

The xrange() function was introduced to solve the memory problem of range(). It was a "sequence type" that generated numbers lazily—one at a time—only when they were needed.

Example:

Python中range与xrange到底有啥区别?-图3
(图片来源网络,侵删)
# In Python 2
my_xrange = xrange(1000000)
# This does NOT create a list of 1,000,000 numbers.
# It just creates a special xrange object that knows how to generate the numbers.
print(type(my_xrange))  # <type 'xrange'>
print(len(my_xrange))   # 1000000 (This is fast because it just stores the start, stop, and step)

Pros:

  • Very memory-efficient. It uses a constant, small amount of memory regardless of the size of the range.
  • Ideal for for loops, where you only need one number at a time.

Cons:

  • You could only iterate over it once. If you tried to loop over it a second time, it would be empty.
  • You couldn't slice it (this would raise a TypeError).

The Modern Era: Python 3

The Python developers realized the confusion and inefficiency of having two functions. They decided to simplify things for Python 3.

range() in Python 3

In Python 3, the range() function behaves exactly like the old xrange(). It is a "sequence type" that generates numbers lazily.

The old, memory-hungry list-based range() from Python 2 was completely removed.

Example:

# In Python 3
my_range = range(1000000)
# This does NOT create a list. It creates a range object.
print(type(my_range))  # <type 'range'>
print(len(my_range))   # 1000000 (Fast, constant time/space)
# You can still get the values by converting it to a list, but that's an explicit action.
# This line WILL create a list in memory and can be slow/memory-heavy.
# my_list = list(my_range) 

Behavior:

  • Memory-Efficient: Like xrange, it uses a fixed amount of memory.
  • Lazy: Numbers are generated on-the-fly during iteration.
  • Iterable: You can loop over it as many times as you want.
  • Slicable: You can slice it (e.g., my_range[500:1000]), which returns another range object.

Comparison Table

Feature range() (Python 2) xrange() (Python 2) range() (Python 3)
Type list xrange object range object
Memory Usage High (stores all numbers) Low (constant memory) Low (constant memory)
Generation Eager (all at once) Lazy (one at a time) Lazy (one at a time)
Iteration Multiple times OK Only once Multiple times OK
Slicing Yes No Yes
Python 3? Removed Removed The only option

Why is range() in Python 3 so efficient?

The range object doesn't store all the numbers. Instead, it stores just three pieces of information:

  1. start
  2. stop
  3. step

When you ask for an item (e.g., my_range[500]), it calculates the value using a simple formula: start + index * step. When you iterate, it just generates the next number in the sequence until it hits the stop value. This is why it's so fast and memory-friendly.

When do you need to convert range to a list?

You should only convert a range to a list if you explicitly need a list of all the numbers in memory. For example:

  • If you need to access elements by index multiple times in a non-sequential way.
  • If you need to modify the list (e.g., sort it, add or remove elements).

For almost all other use cases, especially in for loops, just use the range object directly.

# Good: Iterate (the most common use case)
for i in range(10):
    print(i)
# Good: Get the length
print(len(range(1000000))) # Very fast
# Good: Slice
sub_range = range(10)[3:7]
print(list(sub_range)) # [3, 4, 5, 6]
# Bad (if memory is a concern): Unnecessarily create a huge list
# huge_list = list(range(1000000000)) # This will fail or use all your RAM
分享:
扫描分享到社交APP
上一篇
下一篇