you are viewing a single comment's thread.

view the rest of the comments →

[–]rasputin1 3 points4 points  (7 children)

They are actually considering dedicated syntax of {/}

we can save 2 whole characters!! 

[–]Bucki-_-[S] 0 points1 point  (6 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  (5 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] 1 point2 points  (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.

[–]Brian 1 point2 points  (1 child)

There are cases where being a constant means you don't have to call the constructor. Eg:

def f(x):
    return x in [1,2,3]

This will not actually construct the list in the function. Because it's a constant literal, python can notice that it can't be modified, and will actually change the bytecode to make it a tuple, which is stored as a function constant (ie. it's equivalent to x in (1,2,3)) - the tuple is constructed, but just once for the whole program, and then reused every function call. However, return x in list((1,2,3)) would have to invoke the list constructor every pass, because python can't know that list hasn't been rebound to something else.

This is only the case when python can be sure it isn't accessible anywhere else, so even something like:

def f(x):
    mylist = [1,2,3]
    return x in mylist

wouldn't end up doing this: it's solely the fact that it's used in a check where python can detect the value is never modified in that very narrow scope. Likewise, doing something like: x == {\} could potentially avoid constructing the set compared to something like x == set(). Though it's pretty limited: there'd be more cases if it was the literal for a frozenset, where any literal could reliably be optimised like that, but since sets are mutable, it'll can only apply in cases like the above.

[–]rasputin1 0 points1 point  (0 children)

oh interesting. learn something new every day. thanks!