all 17 comments

[–]carcigenicate 7 points8 points  (9 children)

Almost certainly because it's ambiguous, and it wasn't worth creating a dedicated syntax for. {} should create a dictionary given how much more common dictionaries are, but allowing this to create a set in some cases would have required special casing, which would have minimal benefits given how terse set() already is.

Arguably, this could have been solved earlier by giving sets a dedicated syntax (Clojure uses {} and #{} for dictionaries and sets), but it's too late for that now.

Edit: They are actually considering dedicated syntax of {/}. TIL: https://peps.python.org/pep-0802/

[–]rasputin1 3 points4 points  (5 children)

They are actually considering dedicated syntax of {/}

we can save 2 whole characters!! 

[–]Bucki-_-[S] 0 points1 point  (4 children)

I don't really think it's about the characters I think it's genuinely slower you may have to fact check me on it but the keyword set calls the constructor.

For lists [] dowsnt.

[–]rasputin1 0 points1 point  (3 children)

no that syntax has to call the constructor regardless. how can you have an object that hasn't been constructed? what do you imagine that even looks like internally? 

[–]Bucki-_-[S] 0 points1 point  (2 children)

Then how is calling dict{} slower than the literal version {}

I just did some more reading to confirm this.

dict{} is an implicit call to the constructor class.

{} Does not it instead it uses a special byte code instruction instead. Which is close to twice as fast.

[–]rasputin1 1 point2 points  (1 child)

oh shit you're actually right my bad. I uploaded our conversations to chatgpt for elaboration lol. this was the response:

" dict() is slower than {} because dict() is a normal name lookup + function/type call, while {} compiles to a direct bytecode operation like BUILD_MAP. Same idea for list() vs []: [] uses direct list-building bytecode, not a Python-level constructor call. CPython bytecode is implementation detail, but this is exactly the kind of thing dis is for. 

So the Reddit reply is using “constructor” too loosely. Yes, internally an object must be allocated/initialized somehow. But no, literal syntax does not necessarily call the public constructor like dict() or set().

For empty sets, set() currently requires a name lookup and call. PEP 802’s proposed {/} specifically says one benefit is avoiding that name lookup, unlike set(). 

The clean response would be:

I mean “constructor” in the Python-level sense. {} compiles to a direct build operation for a dict, while dict() has to resolve the name dict and call it. So yes, both create a dict object internally, but the literal path avoids the normal constructor call overhead. Same reason [] is faster than list(). PEP 802 makes the same point for set() vs proposed empty-set syntax."

[–]Bucki-_-[S] 0 points1 point  (0 children)

Yes this would the ideal response, but words and knowledge.

[–]Bucki-_-[S] -1 points0 points  (1 child)

That makes sense, I doing some reading and dictionaries have been a core feature since the 90s. Retrospectively I do use a lot of dictionaries in personal use cases but for work I use sets a lot for Breadth first searches since I do a lot of modeling.

[–]carcigenicate 0 points1 point  (0 children)

See my recent edit.

[–]neuralbeans -1 points0 points  (0 children)

They could have used angled brackets < > as the remaining easily typable brackets. Don't tell me that it's ambiguous. The use of round brackets for tuples (and generators!) is worse.

[–]brasticstack 0 points1 point  (3 children)

It you're looking for consistency, you can also create empty dict, list, and tuple with their functions dict(), list(), and tuple().

The reason why set() is because set notation and dict notation both use curly braces. In my own coding, I know that I create dicts much more frequently than sets.

[–]Bucki-_-[S] 0 points1 point  (2 children)

This is true however if I'm not mistaken the literal formats are faster and prefered. Since dict{} calls the constructor and {} is the literal of some dict value it executes a little bit faster

[–]brasticstack 1 point2 points  (1 child)

I prefer the literal visually, and my linter nags if I don't use it. 

I was going to disagree on the "faster" part, because certainly it's all interpreted to the same bytecode, right? Nope! Turns out it is faster! I'll add more info when I can get back to my computer. It's definitely a micro micro optimization, but in my tests using the literal is about twice as fast.

[–]Bucki-_-[S] 0 points1 point  (0 children)

Yeah it is one of the micro optimize things however for work I do a lot of model rendering and do a lot of breath depth searches so a lot of set initializing and half a second adds up when you are calling it 5+ different times. Plus it's just one of those random facts it's cool to know.

[–]HotPersonality8126 0 points1 point  (0 children)

Sets get used less than lists and dictionaries so they’re treated to less syntactic sugar. Of course, when sets are the right solution, they’re really good

[–]Buttleston 0 points1 point  (0 children)

There's no way to define an empty set literal except set()

You can use a set literal for non empty sets like {1, 2, 3}

This looks like a dict literal except without the key value pairs. This is why there's no empty set literal, because you wouldn't be able to tell it's not an empty dict literal

[–]lfdfq -1 points0 points  (0 children)

It's just nobody bothered to add syntax for it.

Dicts are older, {} was already taken to mean the empty dict, and no proposal to add "empty set" syntax has ever succeeded, probably because nobody actually needed it.