# Possibility to exclude ranges from range

**URL:** <https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885>\
**Category:** Ideas\
**Created:** [June 24, 2026, 11:55am UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885 "2026-06-24T11:55:22Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![du-it](https://avatars.discourse-cdn.com/v4/letter/d/7ba0ec/32.png) [@du-it](https://discuss.python.org/u/du-it)\
**Post date:** [June 24, 2026, 11:55am UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/1 "2026-06-24T11:55:22Z")

</div>

Hi everyone,

I recently came across a scenario where I needed to iterate over a large range of numbers but completely exclude a specific sub-range in the middle (for example, looping from 1 to 100, but skipping 50 to 60).

Furthermore, a common extension of this problem is needing to exclude **multiple, arbitrary sub-ranges** at once (e.g., skipping `50..60`, `75..80`, etc.).

Currently, the idiomatic ways to solve this in Python are:

An explicit `if/continue` block:

Python

```python
for i in range(1, 101):
    if 50 <= i <= 60 or 75 <= i <= 80:
        continue
    # do something

```

Chaining multiple split ranges via `itertools.chain`:

Python

```python
from itertools import chain

for i in chain(range(1, 50), range(61, 75), range(81, 101)):
    # do something

```

Or using an inline list comprehension to filter dynamically:

Python

```python
for i in [x for x in range(1, 101) if not (50 <= x <= 60 or 75 <= x <= 80)]:
    # do something

```

While these approaches work , they quickly become hard to read, require precise mental math regarding the exclusive stop boundaries , or create unnecessary intermediate lists in memory just for filtering.

To improve expressiveness, I would love to propose a way to exclude one or multiple ranges. Taking inspiration from Python’s argument unpacking (`*args`), the feature could accept a variable amount of exclusion ranges:

#### Variant 1: A `.skip()` method on the range object (Backward-compatible)

This uses a `*args` style signature (`def skip(self, *ranges)`), allowing developers to pass as many exclusion ranges or tuples as they need without introducing a new keyword.

Python

```python
# Proposed syntax with a single exclusion:
for i in range(1, 101).skip(range(50, 61)):
    print(i)

# Proposed syntax with multiple exclusions (*args style):
for i in range(1, 101).skip(range(50, 61), range(75, 81)):
    print(i)

```

#### Variant 2: A new `skip` operator/keyword (Syntactic Sugar)

An alternative would be an intuitive infix operator that accepts either a single range or a collection/tuple of ranges.

Python

```python
# Proposed syntax:
for i in range(1, 101) skip (range(50, 61), range(75, 81)):
    print(i)

```

I am aware that introducing a new keyword like `skip` comes with major backward-compatibility hurdles. However, the `.skip(*ranges)` method approach seems like a highly ergonomic, non-breaking addition to Python’s built-in `range` type.

What are your thoughts on extending `range` to natively support one or multiple exclusions? Has something similar been proposed or rejected in the past?

Thanks for your feedback!

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [June 24, 2026, 12:13pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/2 "2026-06-24T12:13:05Z")

</div>

I don’t think it’s necessary for the builtin `range` to do this, but you could define your own. Part of the reason here is that this would get extremely messy if you had different steps, so this would be easiest done with a stepless range alternative. And rather than design new syntax, there’s an obvious one available to you: subtraction!

So here’s what I would recommend:

```python
class MultiRange:
    def __init__ (self, start, stop=None):
        if stop is None:
            start, stop = 0, start
        self.sections = [(start, stop)]
    def __sub__ (self, other):
        # Go through all sections and exclude everything that's covered by other's sections
        # This may involve splitting a range, shortening it at one end, or leaving it as is.
        new_range = type(self)(0)
        # TODO: mutate new_range
        return new_range
    def __iter__ (self):
        for start, stop in self.sections:
            yield from range(start, stop)

```

You may also want to be able to add ranges, too.

Something along these lines should work fairly well. You would be able to do something like:

```python
for i in MultiRange(1, 101) - range(50, 61) - range(75, 81):
    print(i)

```

---

<div class="post-metadata">

**Author:** ![papajoker](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/papajoker/32/12902_2.png) [@papajoker](https://discuss.python.org/u/papajoker)\
**Post date:** [June 24, 2026, 12:25pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/3 "2026-06-24T12:25:11Z")

</div>

or with **sets**?

```python
for i in frozenset(range(1, 101)) - frozenset(range(50, 60)) - frozenset(range(70, 80)):
    print(i)

```

EDIT:

```python
for i in sort(list(
        set(...)
        - set(...)
        - set(...)
    )):

```

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [June 24, 2026, 12:43pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/4 "2026-06-24T12:43:23Z")

</div>

Why frozen? And it might change the order of the resulting elements, which might be a problem.

---

<div class="post-metadata">

**Author:** ![duncathan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/duncathan/32/25521_2.png) [@duncathan](https://discuss.python.org/u/duncathan)\
**Post date:** [June 24, 2026, 12:44pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/5 "2026-06-24T12:44:42Z")

</div>

This may be suitable for sets of integers in CPython, but I have to caution against iterating sets in any situation where the order matters. That’s not an implementation detail I would rely on

---

<div class="post-metadata">

**Author:** ![du-it](https://avatars.discourse-cdn.com/v4/letter/d/7ba0ec/32.png) [@du-it](https://discuss.python.org/u/du-it)\
**Post date:** [June 24, 2026, 12:59pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/6 "2026-06-24T12:59:36Z")

</div>

Thanks for the suggestion! A custom `MultiRange` class is definitely a clever workaround and would solve the problem for an individual project or a custom utility library.

However, the core motivation behind my proposal was to address this at the **built-in language level**.

If every developer has to implement their own `MultiRange` class or carry it around in a personal library across different projects, it defeats the goal of improving Python’s out-of-the-box ergonomics. Since `range()` is one of the most fundamental and frequently used built-ins for loops, having a native way to exclude sub-ranges would eliminate this repeated boilerplate entirely.

That’s why I felt a native `.skip(*ranges)` method on the existing `range` object would be so powerful—it keeps the standard library expressive and prevents developers from reinventing the wheel for a very common looping pattern.

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [June 24, 2026, 1:32pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/7 "2026-06-24T13:32:58Z")

</div>

And what does your AI say about having this on PyPI?

---

<div class="post-metadata">

**Author:** ![JoBe](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jobe/32/26961_2.png) [@JoBe](https://discuss.python.org/u/JoBe)\
**Post date:** [June 24, 2026, 1:46pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/8 "2026-06-24T13:46:51Z")

</div>

I’m actually sad there is no way to like your post multiple times now, but you are right, perhaps it would have been better not to use AI for the OP.

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [June 24, 2026, 2:13pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/9 "2026-06-24T14:13:18Z")

</div>

Nothing here seems overtly AI-generated to me. Whatever you think of AI, it’s not great to use it as a witch-hunt and possibly falsely accuse people.

---

<div class="post-metadata">

**Author:** ![jamestwebber](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jamestwebber/32/12799_2.png) [@jamestwebber](https://discuss.python.org/u/jamestwebber)\
**Post date:** [June 24, 2026, 2:30pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/10 "2026-06-24T14:30:29Z")

</div>

Regardless of whether the OP is using AI to write posts, the more relevant thing is that the idea is not particularly useful.

If you want to skip a subset of a range there are lots of ways to achieve that with plain Python. If you want it to be super-performant then it’s time to implement your own extension, but again this is not a huge obstacle.

I don’t think I’ve ever wished for something like this, because it’s just not a common a use-case in real code–it sounds like a shortcut just for coding challenges.

---

<div class="post-metadata">

**Author:** ![tstefan](https://avatars.discourse-cdn.com/v4/letter/t/f475e1/32.png) [@tstefan](https://discuss.python.org/u/tstefan)\
**Post date:** [June 24, 2026, 2:35pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/11 "2026-06-24T14:35:28Z")

</div>

Agreed. I cannot remember that I ever wanted to remove certain ranges, rather than some indices contained in some set or satisfying some condition. If I could write (analogously to what is possible in comprehensions)

```python
for i in range(a,b) if i is not in excluded_indices:
    ...

```

I probably would do that, but I am also completely fine with

```python
for i in range(a,b):
    if i is in excluded_indices:
        continue
    ...

```

---

<div class="post-metadata">

**Author:** ![jamestwebber](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jamestwebber/32/12799_2.png) [@jamestwebber](https://discuss.python.org/u/jamestwebber)\
**Post date:** [June 24, 2026, 2:37pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/12 "2026-06-24T14:37:49Z")

</div>

Well, you can write (removing the erroneous `is`)

```python
for i in (i for i in range(a,b) if i not in excluded_indices):
    ...

```

But I think the version with a separate `if` statement is clearer to the reader.

---

<div class="post-metadata">

**Author:** ![tapetersen](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tapetersen/32/28049_2.png) [@tapetersen](https://discuss.python.org/u/tapetersen)\
**Post date:** [June 24, 2026, 2:39pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/13 "2026-06-24T14:39:22Z")

</div>

> [@du-it](#):
>
> If every developer has to implement their own `MultiRange` class or carry it around in a personal library across different projects, it defeats the goal of improving Python’s out-of-the-box ergonomics. Since `range()` is one of the most fundamental and frequently used built-ins for loops, having a native way to exclude sub-ranges would eliminate this repeated boilerplate entirely.

That still supposes that this actually is a common case enough that it would need to be repeated.

> [@du-it](#):
>
> While these approaches work , they quickly become hard to read, require precise mental math regarding the exclusive stop boundaries , or create unnecessary intermediate lists in memory just for filtering.

I question both the hard to read argument for the `itertools.chain` based solution as well as the assumption that some skip parameters for the range function would somehow avoid the ambiguities around boundaries (rather than just define it’s own rules people would need to lookup or remember)

I find the `itertools.chain` method very readable and flexible and it also avoids building intermediate lists. I actually have a hard time coming up with an api for range that would be meaningfully shorter or compact. The one negative is really discoverability but I would balance that against the need actually being a lot rarer than assumed here.

> [@jamestwebber](#):
>
> Regardless of whether the OP is using AI to write posts, the more relevant thing is that the idea is not particularly useful.

That wouldn’t be the first on this forum but then respond to that. I agree that the second post has signs enough that I would be _very_ surprised if it wasn’t generated It’s not egregrious enough to be that dismissive about it without addressing the question at all.

That said, please try to use AI where it helps clarity and make the arguments yourself if possible. We’re all here since we enjoy discussing with other people.

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [June 24, 2026, 3:00pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/14 "2026-06-24T15:00:52Z")

</div>

I actually think “ask your favourite chatbot whether this deserves in the Python standardlib” is genuine good advice. AI should be able to tell you ‘no’ and also explain why with more patience that you’re likely to find on a forum.  
But then chatGPT does give me useful answers, and I can’t know it would give the OP equally useful answers.

I’ve not ever needed a `range()` with gaps in it ever, so I don’t think this is a very common desire. And you can achieve what you want very tidily with a 5-line function on a case-by-case basis, or using a class that would require about 20-30 lines to write.  
Python does not add new syntax so that some people can avoid writing 30 lines of code per project. (Though the Annotated syntax that’s being discussed wouldn’t save that many lines per project would it? And it is still being seriously considered.)

---

<div class="post-metadata">

**Author:** ![JoBe](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jobe/32/26961_2.png) [@JoBe](https://discuss.python.org/u/JoBe)\
**Post date:** [June 24, 2026, 3:05pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/15 "2026-06-24T15:05:23Z")

</div>

> [@peterc](#):
>
> Though the Annotated syntax that’s being discussed wouldn’t save that many lines per project would it? And it is still being seriously considered.

It’s not really _new syntax_ being added. Similar to e.g. strings supporting `+`, it’s just using existing syntax that’s being exposed via a method for the operator.

But this is a bit off-topic, so I’d like to get back to the topic. I think the general message most people here want to get to the OP stays the same, as adding ±2 lines for some feature that’s not used often doesn’t hurt a lot.

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [June 24, 2026, 3:20pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/16 "2026-06-24T15:20:21Z")

</div>

yes I should have use the word “features” instead of “syntax”. My bad.

For what it’s worth, I think you could write the desired class approximately like this

```python
class Range:
    ranges: list[range]

    def __init__ (self, start=None, stop=None, ranges=None):
        if ranges is None:
            ranges = []
        if start is not None:
            ranges += [range(start, stop)]
        self.ranges=ranges

    def __iter__ (self):
        for r in self.ranges:
            yield from r

    def skip(self, start, stop):
        bot_ranges = [
            range(r.start, min(r.stop, start))
            for r in self.ranges
            if r.start < start
        ]
        top_ranges = [
            range(max(r.start, stop), r.stop)
            for r in self.ranges
            if r.stop > stop
        ]
        return Range(ranges=bot_ranges + top_ranges)

    def __repr__ (self):
        return f"Range({self.ranges})"

```

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [June 24, 2026, 4:09pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/17 "2026-06-24T16:09:41Z")

</div>

The itertools approach remains the simplest way to concatenate generators generally.

The proposed “skip” keyword/method is likely complexifying the python API without being an essential addition.

For your insight, this is a cleaner syntax for a list concatenation :

```python
list(range(5)) + list(range(8, 13))

```

Yet it would create temporary lists before the final one, thus is not the best performance option.

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [June 24, 2026, 4:21pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/18 "2026-06-24T16:21:19Z")

</div>

@hprodh Or:

```python
*range(5), *range(8, 13)

```

---

<div class="post-metadata">

**Author:** ![du-it](https://avatars.discourse-cdn.com/v4/letter/d/7ba0ec/32.png) [@du-it](https://discuss.python.org/u/du-it)\
**Post date:** [June 24, 2026, 4:46pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/19 "2026-06-24T16:46:28Z")

</div>

Yes, I am using an LLM to help me structure my thoughts and translate them into clear English, as it is not my native language. I apologize if it sounds or ist AI-style. However, the idea for `.skip()` is entirely my own—I just found the current workarounds a bit cumbersome and wanted to see if others felt the same way.

I really want to thank my supporters here who stepped in to keep the focus on the actual technical concept rather than the drafting tools!

At the same time, I completely understand the perspective of the skeptics who want to keep the core language and the `range` object as minimal and pure as possible. Python’s simplicity is its greatest strength, and adding features blindly can clutter the language.

However, to address the feedback regarding `itertools.chain` vs. `.skip()`:

While the typing effort for a single exclusion seems similar, the real power of a native `.skip(*ranges)` method lies in reducing cognitive load, avoiding off-by-one errors with Python’s exclusive upper boundaries, and—crucially— **maintainability**.

Consider this direct comparison when excluding the exact same three blocks:

Python

```python
# The current way using itertools.chain:
# Highly prone to off-by-one errors; the original intent (1 to 100) is completely lost visually.
for i in chain(range(1, 30), range(41, 55), range(66, 80), range(91, 101)):
    ...

# The proposed ergonomic way:
# The main intent (1 to 100) remains perfectly clear, followed by a clean 'blacklist'.
for i in range(1, 101).skip(range(30, 41), range(55, 66), range(80, 91)):
    ...

```

Now, imagine you want to change the upper limit of the main loop later on (e.g., from `100` to `500`).

- With the `chain` approach, you have to find and modify the very last range at the end of the expression (`range(91, 501)`), which feels counter-intuitive and disconnected.

- With the `.skip()` approach, you simply change the main range at the very beginning (`range(1, 501)`), while your blacklist remains completely untouched.

Python has a beautiful history of adding syntactic sugar and ergonomic features purely to make code more expressive and human-readable, even if a functional alternative already existed—think of the ternary operator (`x if condition else y`), the walrus operator (`:=`), or string `.join()`.

The string `.strip()` method is another great example: we use it because it’s convenient and expressive, even though we could technically achieve the same result with manual string slicing. A `.skip()` method on `range` feels like a natural extension of that same pragmatic Python philosophy: making common, repetitive logic clear at a single glance without forcing developers to reinvent the wheel every time."

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [June 24, 2026, 5:11pm UTC](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885/20 "2026-06-24T17:11:54Z")

</div>

I think the principle “not every 3-line function needs to be a builtin” applies here. The usefulness of the feature is limited (I know you claim you’ve needed it often, but in my experience I’ve never seen anyone else express a need for this functionality), and it’s relatively easy to implement yourself in a few lines of code (you can make the solution as complex and general as you like, but the simple form is straightforward).

> [@du-it](#):
>
> However, to address the feedback regarding `itertools.chain` vs. `.skip()`

Yes, `chain()` obscures the upper limit to an extent. But there’s also:

```python
for i in (i for i in range(1,101) if not (30 <= i < 40 or 55 <= i < 65 or 80 <= i < 91)):
    ...

```

That directly expresses the intent (i in the given range unless it’s in one of the excluded subranges). It’s a little verbose (“`for i in (i for i in...`” is clumsy) but that’s a known aspect of a standard language feature, and hardly a disaster.

Add to that the fact that supporting this within the existing `range()` object would probably add extra complexity, and hence worsen performance, even in the typical case of no exclusions. For something as commonly used as `range`, that’s not a good trade-off.

Sorry, but I’m -1 on the proposal.

[Next page](https://discuss.python.org/t/possibility-to-exclude-ranges-from-range/107885.md?page=2)
