But to my surprise, the language reference says that this is an implementation detail:
An empty pair of parentheses yields an empty tuple object. Since tuples are immutable, the same rules as for literals apply (i.e., two occurrences of the empty tuple may or may not yield the same object).
Is it maybe time to guarantee this property as part of the language spec? I can’t see us ever realistically changing this, as I think it would break too much code.
I suppose adding it to the language spec would mean that other implementations would also have to make sure that () was implemented as a singleton. But I would guess that they all already do, because it’s used as a singleton so much in the wild. From experimenting locally, at least PyPy already does.
If it helps for some additional context from alternate implementations (picked entirely because I already had them installed):
GraalPy doesn’t appear to do this.
Python 3.11.7 (Mon Oct 07 10:19:29 UTC 2024)
[Graal, Oracle GraalVM, Java 24 (amd64)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x = ()
>>> y = ()
>>> x is y
False
Micropython does.
MicroPython v1.21.0 on 2024-04-22; linux [GCC 11.4.0] version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> x = ()
>>> y = ()
>>> x is y
True
Indeed, Python 3.14 (and maybe 3.13?) considers the latter worthy of a SyntaxWarning (as I found out while checking whether the singleton check was handled inside or outside PyTuple_New):
>>> import ctypes
>>> ctypes.pythonapi.PyTuple_New.restype = ctypes.py_object
>>> ctypes.pythonapi.PyTuple_New(0)
()
>>> ctypes.pythonapi.PyTuple_New(0) is ()
<python-input-4>:1: SyntaxWarning: "is" with 'tuple' literal. Did you mean "=="?
ctypes.pythonapi.PyTuple_New(0) is ()
True
Yes, that’s a very good point, and suggests that those who are using () as a sentinel value should probably stop doing so. That’s pretty persuasive that we should therefore leave this as an implementation detail.
Sentinels have been the subject of a lot of discussion. PEP 661 tried
to codify a sentinel type that solves some of the issues of
identification that have been mentioned already. Didn’t seem to get
enough traction to move all the way through the process, but it’s still
a place where a lot of thoughts around the situation were recorded, may
be worth a look.