ARTICLE AD BOX
You should probably use a sentinel value. In Python 3.14 and earlier, this is typically (though not always!) done using a bare object combined with an identity (is) check:
import ast SENTINEL = object() user_input = SENTINEL while user_input is SENTINEL: try: user_input = ast.literal_eval(input("Enter a Python literal: ")) except: passThe benefit of this pattern is that SENTINEL is completely unique. No other user-created object will ever compare identical to it. As such, there's no chance of collision with user-provided input; even another object() will not be identical to your sentinel. In fact, you can create multiple unique sentinels for different use cases:
SENTINEL_1 = object() SENTINEL_2 = object() assert SENTINEL_1 is not SENTINEL_2Be careful to always use identity, not equality (==), when comparing to sentinels. Otherwise, someone could redefine __eq__ on the other object in an undesirable way:
SENTINEL = object() class AlwaysEqual: def __eq__(self, other, /): return True assert SENTINEL is not AlwaysEqual() assert SENTINEL == AlwaysEqual() # Bad!In Python 3.15, using an object like this will no longer be necessary. PEP 661 introduced a built-in sentinel class, which is very similar to the old pattern:
SENTINEL = sentinel("SENTINEL") assert SENTINEL is not None SENTINEL_2 = sentinel("SENTINEL_2") assert SENTINEL is not SENTINEL_2Like an object sentinel, new sentinels should always be compared with is and not ==.
It will also play nicely with type hints (though in this case, a bare None would also work):
SENTINEL = sentinel("SENTINEL") five_characters: str | SENTINEL = SENTINEL while five_characters is SENTINEL: user_input = input("Enter five characters: ") if len(user_input == 5): five_characters = user_inputBefore 3.14, this wouldn't have worked; you generally would've needed to introduce more overhead such as using a class rather than an object as your sentinel value.
