And for natural parallel, a_set['this'] would be equivalent to 'this' in a_set. It would make sets functionally equivalent to dictionaries that lack values and only test for presence.
I don’t know if there’d be weird consequences of this, though. And frankly, I have much more frequently just used a dictionary, since it’s not worth bothering with a set when a dict does everything more conveniently.
I could use some performance upgrade. And I use set, because it is the right thing for the task… Never thought of using dict, but will start using it I suppose.
Before sets even existed in the stdlib, the general feeling was that you didn’t need sets because you could just use a dict with dummy values (e.g. None). x in a, a[x] = None, del a[x], x.pop(x, None) were considered perfectly fine idioms. Then Greg Wilson suggested that such syntax was actually verbose and confusing, and sets.py was born with PEP 218 (in 2000), and in Python 3 they became built-ins.
Now somehow there’s a proposal to go back to pretending they’re dicts? That sounds like a big step backwards to me.
You can use string input of the float constructor to make these objects. Though, I would buy rather some predefined builtin constants to input such things.
But all this can be easily solved by one-liners like ∅ = frozenset(), oo = float(“inf“) or from math import inf as oo in user code.
The PEP argument “Sets are currently the only built-in collection type that have a display syntax, but no notation to express an empty collection.“ sounds as “consistency“ argument for me. I doubt that new cryptic syntax will be obvious for beginners. It certainly doesn’t obvious for me, though can be learned and easily remembered.
That would mean that ∅ would always be equal to the exactly same set and I can’t imagine a use case where sharing it would make sense across code. Perhaps I’m missing something, but that wouldn’t help, except for people wanting to check against empty sets, where the user could also just do empty = s{} or empty = {-} or similar.
I prefer this * notation. I like the idea of this PEP in concept, but the {/} syntax feels rather arbitrary and unlike anything else in the language.
Using * instead has some nice symmetry and “feels” more Pythonic.
{*args} creates a set with some unpacked values.
{*} creates an empty set.
{**} creates an empty dictionary. {} is still the normal form most people would use, but it would be included for the sake of internal consistency.
In fact, I’d go one step further and add the option to lists and tuples too: [*] and (*) can be aliases for [] and (). It wouldn’t be the common way to make lists and tuples, but it would make everything feel fairly consistent: [*args], [*], (), {*}, {**}, {}.
The need for such comparison in a loop is rare, and when needed, put fset = frozenset() before the loop and compare to the immutable constant fset (or FSET).
Yes, which is why I specifically said in my post it’s for testing if a set is empty in an expressive manner.
To me at least, s == frozenset() is by far the most readable way to express the intent of testing if s is an empty set. It’s just because most of us know that it isn’t efficient and it’s rather verbose that we’d settle with the two alternatives you mentioned and that we don’t see such an expression used often.
If you’re checking both that s is a set and that it’s empty, maybe. But most of the time[1] you’re probably sure that s is a set, and all you’re interested in is “is the set empty” - for which the canonical test is if not s (or if you don’t like automatic boolean conversion, if len(s) == 0).
If you are wanting to check that s is a set and it’s empty, I’d argue that if isinstance(s, set) and len(s) == 0 is far more readable, but I don’t really care to debate questions of readability here, as it’s so subjective. I’m pretty sure that needing the double test is very rare, no matter how you choose to express it.
Particularly if you’re type checking your code! ↩︎
But if folks want to add syntactic sugar, I like the suggestion of a prefix, like what is possible with strings. E.g., s{} for empty set, d{} for empty dict (maintaining {} for legacy reasons). And this method scales simply, as there could easily be fs{} for frozen sets.
This approach of prefixing could even be applied to comprehensions.
Improving readability is all about reducing the mental load placed on a reader. By using not s you’re asking the reader to recall what name s is defined as before understanding what the not operator is doing.
It’s why we see expressions using x == 0, x == '', x == [], etc. all over the place instead of not x even when it’s almost always not necessary to test the type on the left, even when readers can infer themselves the type of the expression on the left:
Similarly, using x == frozenset() to test if a set is empty would be both clearer and recommended if there were an empty frozenset literal to allow the expression to be both concise and efficient.
However, if a single comma were to be used to represent an empty collection, it may be confusing why this could not be used for empty tuples or lists. In time, there might be proposals to add support for [,] and (,).
To be honest, I was a little surprised when I read this that (,) wasn’t already supported. Because (1) is an integer and (1,) is a tuple, my immediate intuition was that (,) was also a valid tuple, even though I don’t think I’ve ever tried to use that. I seem to remember that I learned the (1) versus (1,) distinction long ago with a slightly misleading phrase like “It’s the comma that makes it a tuple, not the parenthesis”.
I’m mostly neutral on the proposal overall, but think that {,} (and (,) being a valid option) would be a more natural spelling for the idea.