# Stripping Strings in Python? You Might Be Doing It Wrong
> Learn the key differences between `removesuffix()` and `rstrip()` in Python. Avoid common pitfalls and choose the right method for precise string manipulation.

Canonical: https://blog.abhimanyu-saharan.com/posts/stripping-strings-in-python-you-might-be-doing-it-wrong
Published: 2025-06-30
Last updated: 2025-06-30
Authors: Abhimanyu Saharan
Categories: Python

When working with strings in Python, you might come across two methods that sound like they could do similar jobs: **`removesuffix()`** and **`rstrip()`**. Both deal with removing characters from the end of a string, but they work in very different ways. If you’re new to Python string methods, it’s important to understand these differences to avoid unexpected behavior. In fact, Python introduced `removeprefix()` and `removesuffix()` in Python 3.9 _specifically_ because many users were confused by how `strip()` and its variants worked.

In this tutorial, we’ll explain what each method does, how they differ, and when to use one over the other. We’ll walk through simple code examples (including some tricky edge cases) to illustrate each point. By the end, you should have a clear understanding of `removesuffix()` vs `rstrip()` and best practices for using them.

## What is `str.removesuffix()`?

The `removesuffix()` method **removes a specific substring from the end of a string** if it exists. In other words, it checks if the string ends with the given suffix and, if so, returns a new string with that suffix chopped off. If the string doesn’t end with that substring, it returns the original string unchanged. Importantly, the argument to `removesuffix()` is interpreted as an **exact substring**, _not_ a collection of characters. This means it looks for that whole sequence at the end of the string.

**Key points about `removesuffix():`**

- **Usage:** `your_string.removesuffix(suffix)`
- **Purpose:** Remove _one exact_ suffix substring from the end if present (if the string ends with `suffix`).
- **Behavior:** If the string ends exactly with `suffix`, it returns the string minus that suffix. If it doesn’t, the string is returned unchanged. (It does _not_ do any partial or character-wise stripping.)
- **Python Version:** Available in Python 3.9 and above. (It will raise an `AttributeError` in earlier versions.)
- **No Default Argument:** You must provide a suffix string. If you call it with no argument, you get a `TypeError` (unlike `rstrip` which has a default behavior)

For example, using `removesuffix()` to remove a file extension from a filename:

```python
file_name = "archive.zip"
print(file_name.removesuffix(".zip"))   # Output: "archive"
print(file_name.removesuffix(".rar"))   # Output: "archive.zip" (unchanged, suffix not found)
```

In the first case, `"archive.zip".removesuffix(".zip")` returns `"archive"` because the string ends with `".zip"`. In the second case, since `"archive.zip"` does _not_ end with `".rar"`, the original string is returned unchanged.

Notice that `removesuffix()` cleanly removes the exact suffix **as a whole unit**. It won’t touch the string unless the entire substring matches the end. If the suffix appears elsewhere or only partially at the end, it’s not removed. Also, `removesuffix()` will remove only one occurrence of the suffix at the very end, even if the suffix might appear twice in a row (we’ll see an example of this later). This method provides a clear and predictable way to remove a known ending from a string.

## What is `str.rstrip()`?

The `rstrip()` method (short for “right strip”) **removes trailing characters based on a set of specified characters**. By default (with no arguments), `rstrip()` will strip away any whitespace characters (spaces, newlines, tabs, etc.) from the end of the string. If you provide the optional `chars` argument, `rstrip(chars)` will treat those characters _as a set_ and remove _any combination of them_ from the end of the string. 

This continues until a character not in the set is encountered.

**Key points about `rstrip():`**

- **Usage:** `your_string.rstrip([chars])` (the `chars` argument is optional).
- **Purpose:** Remove _any trailing characters_ that are in the specified set. Commonly used to trim whitespace or unwanted characters from the end of a string.
- **Behavior:** If `chars` is provided, each character in that string is considered a **character to strip**, not a literal suffix. Python will chop off as many of those characters at the end of the string as it can, **repeatedly**, until it hits a character not in the set. If `chars` is omitted, it defaults to removing all types of whitespace.**Default Whitespace Trimming:** `your_string.rstrip()` (with no arguments) is a handy way to remove newlines or spaces at the end of a string (for example, when reading lines from a file).**No Error on Omission:** Unlike `removesuffix`, you can call `rstrip()` with no arguments; it simply assumes whitespace stripping.

To illustrate basic `rstrip` usage, here’s an example trimming whitespace:

```python
line = "Hello World   \n"
print(repr(line))          # Output: "'Hello World   \\n'" (repr shows the whitespace and newline)
print(repr(line.rstrip())) # Output: "'Hello World'" (trailing spaces and newline removed)
```

In the `repr()` output above, you can see that `rstrip()` removed the three spaces and the newline character at the end of the string, leaving `"Hello World"`. This is the typical use of `rstrip()`, cleaning up trailing whitespace.

Now, if we use `rstrip(chars)` with specific characters, remember: **the argument is treated as a set of characters, not a sequence**. For example, calling `'ABC123'.rstrip('3C')` will remove any trailing `'3'` or `'C'` characters from the end of the string. It does _not_ look for the substring `"3C"` as a unit. If the string ended in `"C3C"`, it would remove the trailing `C`, then `3`, then `C` again, because those are all in the set `{ '3', 'C' }`.

In short, `rstrip()` is very useful for general trimming tasks, but it doesn’t know anything about _substrings_ – it only looks at individual characters. This is where confusion often arises for beginners, as we’ll explore next.

## Differences Between `removesuffix()` and `rstrip()`

Despite both methods dealing with the end of strings, they have fundamental differences in their approach. Here’s a breakdown of how `removesuffix()` and `rstrip()` differ:

- **Argument Interpretation:** `removesuffix()` treats its argument as a **literal substring**, whereas `rstrip()` treats its argument as a **set of characters**. This means `removesuffix("abc")` will only remove the exact sequence `"abc"` if it’s at the end, while `rstrip("abc")` will remove _any_ trailing `a`, `b`, or `c` characters in any order or combination.**Operation Mechanism:** `removesuffix()` performs a single check and removal, at most one suffix will be removed (it does not loop or repeatedly trim). In contrast, `rstrip()` continues stripping character by character until it encounters a character not in the specified set, which can remove multiple occurrences or even multiple kinds of characters in one go.
- **Use Case Intent:** Use `removesuffix` when you have a **specific ending** you want to remove (like a file extension or a known suffix in data). Use `rstrip` when you want to **trim off any of a set of characters** (like whitespace or punctuation) regardless of order. For example, to remove a trailing newline or period from user input, `rstrip` is appropriate; to remove a `".txt"` file extension, `removesuffix` is safer.**Default Behavior:** Calling `rstrip()` with no arguments will strip whitespace by default. Calling `removesuffix()` with no arguments is not allowed, you must specify a suffix (if you forget to pass an argument, you get an error).
- **Outcome If Not Present:** If the specified substring is not at the end, `removesuffix()` simply returns the original string (no change). Similarly, if none of the `chars` are at the end of the string, `rstrip(chars)` will return the original string unchanged. The difference is that `rstrip` might still alter the string if _some_ of the characters in its set match the ending even if the entire intended substring isn’t there (this can lead to accidental removals, see pitfalls below).

To make these distinctions clearer, let’s consider a scenario that highlights the difference. Suppose we have a URL and we want to remove a specific path suffix from it:

```python
url = "https://example.com/api"
print(url.removesuffix("/api"))  # Expected: "https://example.com"
print(url.rstrip("/api"))       # ???
```

What do you think the second line will output? Intuitively, one might expect it to also give `"https://example.com"`. However, using `rstrip("/api")` doesn’t mean “remove the substring `/api`”, it means “remove any `/`, `a`, `p`, or `i` characters from the end of the string.” This subtle difference can produce a surprising result. In this case, `url.rstrip("/api")` would output:

```python
print(url.rstrip("/api"))  # Output: "https://example.com" (surprise!)
```

Instead of removing the substring `"/api"` cleanly, it removed the characters `'a'`, `'p'`, `'i'`, and `'/'` wherever it found them at the end. The URL string `"https://example.com/api"` ends with the sequence `"/api"`. `rstrip` will remove the `i`, then `p`, then `a`, then `/`. But after removing `"/api"`, it doesn’t stop – now the string ends in `"...example.com"` which ends in `'m'`. Since `'m'` is not in the set `{ '/', 'a', 'p', 'i' }`, it stops there. The result is `"https://example.com"`.

The correct way to handle that case would be using `removesuffix("/api")`, which only removes the exact `/api` if it’s the suffix, leaving the rest of the string intact.

In summary, `removesuffix()` provides a precise, all-or-nothing removal of a substring at the end, whereas `rstrip()` provides a broad, character-based trimming. Next, we’ll see more concrete examples to drive these differences home.

## Code Examples and Edge Cases

Let’s run through some simple code examples to see the behaviors of `removesuffix()` and `rstrip()` in action. These examples include a few edge cases that commonly trip up beginners.

**Example 1: Removing a File Extension**  
Imagine you have filenames and you want to remove the file extension if it’s “.txt”. We’ll compare `removesuffix()` and `rstrip()` for this task:

```python
filename1 = "report.txt"
print(filename1.removesuffix(".txt"))   # Output: "report"
print(filename1.rstrip(".txt"))        # Output: "repor"  (oops, lost the 't'!)

filename2 = "report.tx"
print(filename2.removesuffix(".txt"))  # Output: "report.tx"  (unchanged, suffix not present)
print(filename2.rstrip(".txt"))       # Output: "repor"      (removed "tx" erroneously)
```

Let's break down what happened:

- For `"report.txt"`: `removesuffix(".txt")` correctly gave `"report"`. But `rstrip(".txt")` returned `"repor"`, which is missing the last letter **t**. Why? Because `rstrip(".txt")` treated the characters `{'.', 't', 'x'}` as the set to strip. It removed the `.`, then the `t`, then the `x` from the end of `"report.txt"`. At that point the string ended in `"t"` (the last letter of `"report"`), and since `'t'` is also in the set, it stripped that too! The result was `"repor"`. This is a clear pitfall: using `rstrip` to remove a substring can accidentally remove characters that were never part of the suffix, if they coincide with the characters in the suffix. In contrast, `removesuffix` only took off the exact substring `".txt"`, leaving `"report"` intact.
- For `"report.tx"`: Here the string does _not_ actually end in `".txt"` (it’s missing the final `t`). `removesuffix(".txt")` correctly left the string unchanged (`"report.tx"`) since the exact suffix wasn’t present. But `rstrip(".txt")` still removed characters! It saw that the string ended in `"tx"`, and since both `'t'` and `'x'` are in the set of characters, it stripped them, again leaving `"repor"`. This shows how `rstrip` can produce an unintended result even when the intended substring isn’t at the end, as long as some of those characters are there, it will strip them.

**Example 2: Removing Trailing Punctuation**  
Now let’s look at a scenario where `rstrip` is actually handy: say we have a string with trailing question marks and we want to remove _all_ the `?` at the end:

```python
text = "Hello???"
print(text.removesuffix("?"))  # Output: "Hello??"
print(text.rstrip("?"))        # Output: "Hello"
```

Here, our string is `"Hello???"`.

- `removesuffix("?")` only takes off **one** `"?"` from the end, because it only removes one exact suffix per call. After one removal, the string would become `"Hello??"`. (If we called it again on the result, it would remove one more, and so on.)
- `rstrip("?")` removes **all trailing** `"?"` characters in one go. It sees a `?` at the end and removes it, then sees another `?` (still at the end) and removes it, and so forth until no more `?` remain at the end. The result is `"Hello"` with all three question marks gone. This is exactly what we want when cleaning up trailing punctuation or whitespace.

As this example shows, if you need to strip _multiple occurrences_ of a character or set of characters, `rstrip` is very convenient – it saved us from writing a loop or calling `removesuffix` multiple times. On the other hand, if we only wanted to remove _one_ question mark and keep the rest, `removesuffix` would be the way to go.

**Example 3: Suffix vs Character Stripping**  
Consider a string that contains a repeated suffix sequence: `"foobarbar"`. This string ends with `"barbar"`, which is `"bar"` repeated twice. Let’s see how each method handles this:

```python
s = "foobarbar"
print(s.removesuffix("bar"))  # Output: "foobar"
print(s.rstrip("bar"))        # Output: "foo"
```

- `s.removesuffix("bar")` checks if `"foobarbar"` ends with `"bar"` – it does, so it removes that substring, resulting in `"foobar"`. It stops there. The string `"foobar"` no longer ends in `"bar"`, so one removal was enough.
- `s.rstrip("bar")` treats the characters `{ 'b','a','r' }` as the set to strip. Starting from the end of `"foobarbar"`, it will remove any `b`, `a`, or `r`. The original string ends in "...barbar". The method will strip off `"bar"` (because those are valid chars to remove), leaving `"foobar"`. But now `"foobar"` **still ends in "bar"** (because "foobar" ends with "bar" as well). `rstrip` continues stripping because it sees an `'r'` at the end (which is in the set), then an `'a'`, then a `'b'`. It ends up removing the second `"bar"` as well! The final result is `"foo"`. Essentially, `rstrip("bar")` kept removing `b`, `a`, `r` until none were left at the end, which nuked both occurrences of the suffix. In contrast, `removesuffix("bar")` only removed the last occurrence and then stopped.

This demonstrates that `rstrip` doesn’t understand the concept of “one suffix at a time” – it just strips characters blindly until it can’t anymore. If that’s what you want (remove _all_ instances of those trailing characters), great. But if you only meant to remove one suffix, `rstrip` can overshoot.

**Example 4: The “Banana” Problem (Unexpected Over-Stripping)**  
To drive home the difference, let’s use a more playful example. Suppose you have the string `"banana"` and you want to remove a trailing `"na"`. Intuition might suggest both methods yield the same result, but let’s see:

```python
fruit = "banana"
print(fruit.removesuffix("na"))  # Output: "bana"
print(fruit.rstrip("na"))       # Output: "b"
```

Why did `"banana".rstrip("na")` result in just `"b"`? Here’s what happened: `rstrip("na")` treats the set of characters `{ 'n', 'a' }`. The string `"banana"` ends with `"na"`. `rstrip` sees an `'a'` at the end and removes it, then sees an `'n'` (now at the end) and removes it, then sees another `'a'` now at the end (from the middle of "banana") and removes it, and so on – it will remove every trailing `'n'` or `'a'` it finds. In fact, `"banana"` is composed only of `b`, `a`, and `n`, so once it starts stripping from the right, it will remove _all_ the letters until it hits `'b'`, which is not in the set. The end result is `"b"`. On the other hand, `removesuffix("na")` looked for the exact substring `"na"` at the end and found it, then simply chopped that off, leaving `"bana"`. It didn’t touch the rest of the string after that.

This “banana” example is admittedly contrived, but it’s a good mental model: `rstrip` will peel your string like a banana, removing layer after layer of specified characters, whereas `removesuffix` will precisely cut off a single defined piece at the end.

## Summary and Best Practices

In summary, `removesuffix()` and `rstrip()` are both useful string methods, but they serve different purposes:

- **`removesuffix()`** was designed to do exactly what its name implies: remove a specific suffix if present. It doesn’t guess or generalize; it either finds that exact ending or leaves the string alone. This makes it **predictable and safe** for tasks like removing file extensions, URL fragments, or any known substring from the end of a string. If you’re on Python 3.9+, prefer `removesuffix` (and its sibling `removeprefix`) for clarity when you mean to cut off a specific affix. This method exists because many beginners expected `rstrip` to work this way and were surprised when it didn’t.
- **`rstrip()`** is your go-to for cleaning up **trailing miscellaneous characters**. Need to strip whitespace? `rstrip()` (with no arguments) has you covered. Need to remove any trailing dots or commas or a mix of characters? `rstrip(".,")` will happily trim all trailing periods or commas. Just remember that it’s not checking for a sequence, only individual characters. A good mental check is to ask: “Am I trying to remove a _word/substring_ or just _characters_?” If it’s a word or specific sequence, `removesuffix` is likely what you want. If it’s classes of characters (like "any whitespace" or "any of these symbols"), `rstrip` is appropriate.

**Best practice:** **Use the right tool for the job.** If you want to remove a **specific ending substring**, use `removesuffix()` for clarity and correctness. If you want to **trim trailing characters in general**, use `rstrip()` but be cautious with the characters you pass in. As we saw, misusing `rstrip` for substring removal can lead to dropping unintended characters. Always consider what characters might be stripped. When in doubt, test with a few examples (as we did above) to ensure the method behaves as you expect.

Finally, if you’re working with an older Python version that doesn’t have `removeprefix/removesuffix`, you can achieve similar results with techniques like slicing or `str.endswith()` checks. However, if you have the option, using `removesuffix` makes your code more readable and less error-prone for those specific cases.

**Takeaway:** For beginners and experienced developers alike, understanding this distinction prevents a lot of bugs. `removesuffix()` gives you a scalpel for precise suffix removal, while `rstrip()` is a broad brush for cleaning off unwanted trailing characters. Choose accordingly, and your string-manipulating code will be both safe and clear!

## FAQ

### Can rstrip() be used to remove a specific word or substring?

No. `rstrip()` removes individual characters from the end of a string based on a set, not a specific substring. To remove a word or suffix, use `removesuffix()` instead.

### What happens if I use removesuffix() with a suffix that’s not present in the string?

Nothing changes. `removesuffix()` returns the original string unchanged if the given suffix is not found at the end.

### Is removesuffix() available in all versions of Python?

No. `removesuffix()` was introduced in Python 3.9. For earlier versions, use `str.endswith()` with slicing as a workaround.

### Does rstrip() remove all occurrences of characters or just one?

`rstrip()` removes **all trailing** characters that are part of the given character set, continuing until it encounters a character not in that set.

### Can rstrip() accidentally remove important data from a string?

Yes. If the characters you pass to `rstrip()` appear in unintended places at the end, it may remove more than you expect. Use it carefully when trimming anything other than whitespace.
