Well, please post examples of *real-world* use cases where it makes a
difference.
Otherwise, you're asking us to add hacks to the implementation just to
make you feel good, which is quite unacceptable.
Regards
Antoine.
People get hung up on all sorts of things. I would hate to think we would
complicate the implementation to pander to pointless micro-optimization.
I'm sure that there are many far more important things than this.
> - it can make a difference, for example setting up a dict with many keys
>at the core of a type loop.
Ah yes, the semi-mythical "tight loop".
I've never come across one of these tight loops that creates a dict with
many keys in a tight loop, and then apparently fails to actually use it
for anything useful. For if it did, surely the actual work done with the
dict is going to outweigh the setup cost for all but the most trivial
applications. I find it hard to get uptight about a small inefficiency
in trivial applications that don't do much.
Show me a non-toy use-case where creating dicts is an actual bottleneck,
and I'll revise my position.
> Without looking at implementation, they should logically perform the same...
I disagree. Calling dict() has to do a name lookup, and then a function
call. That alone is almost 2.5 times as expensive as creating a dict
literal on my machine:
[steve@ando ~]$ python3.3 -m timeit "d = {}"
10000000 loops, best of 3: 0.17 usec per loop
[steve@ando ~]$ python3.3 -m timeit "d = dict()"
1000000 loops, best of 3: 0.416 usec per loop
Then you have the function call itself, which engages the argument parsing
mechanism, which does more work than dict literal syntax. For example, it
checks for duplicate keyword arguments, while dict literals happily accept
duplicate keys.
It's hardly a surprise that dict() is slower than {}.
--
Steven
To (mis-)quote Antoine:
>--> d1 = {1:2}
>--> d2 = {'3':4}
>--> dict(d1, **d2)
> {1: 2, '3': 4}
Apparently it is valid syntax. Just make sure you keys for the ** operator are valid strings. :)
I posted this (by accident) off the list:
> On 2012-11-14, at 23:43 , Chris Withers wrote:
>
>> On 14/11/2012 22:37, Chris Withers wrote:
>>> On 14/11/2012 10:11, mar...@v.loewis.de wrote:
>>>> def xdict(**kwds):
>>>> return kwds
>>>
>>> Hah, good call, this trumps both of the other options:
>>>
>>> 1000000 -r 5 -v 'def md(**kw): return kw; md(a=1,b=2,c=3,d=4,e=5,f=6,g=7)'
>>> raw times: 0.548 0.533 0.55 0.577 0.539
>>> 1000000 loops, best of 5: 0.533 usec per loop
No, this just doesn't execute the right code:
>>> def md(**kw): return kw; md(a=1,b=2,c=3,d=4,e=5,f=6,g=7)
...
>>> import dis
>>> dis.dis(md)
1 0 LOAD_FAST 0 (kw)
3 RETURN_VALUE
4 LOAD_GLOBAL 0 (md)
7 LOAD_CONST 1 ('a')
10 LOAD_CONST 2 (1)
13 LOAD_CONST 3 ('b')
16 LOAD_CONST 4 (2)
19 LOAD_CONST 5 ('c')
22 LOAD_CONST 6 (3)
25 LOAD_CONST 7 ('d')
28 LOAD_CONST 8 (4)
31 LOAD_CONST 9 ('e')
34 LOAD_CONST 10 (5)
37 LOAD_CONST 11 ('f')
40 LOAD_CONST 12 (6)
43 LOAD_CONST 13 ('g')
46 LOAD_CONST 14 (7)
49 CALL_FUNCTION 1792
52 POP_TOP
Also:
Python 3.2.3 (default, Apr 11 2012, 07:12:16) [MSC v.1500 64 bit
(AMD64)] on win 32
Type "help", "copyright", "credits" or "license" for more information.
>>> dict({1: "foo"}, **{frozenset([2]): "bar"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
While:
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> dict({1: "foo"}, **{2: "bar"})
{1: 'foo', 2: 'bar'}
>>> dict({1: "foo"}, **{frozenset([2]): "bar"})
{1: 'foo', frozenset([2]): 'bar'}
If you're worrying about global lookup, you should stop (in this case):
$ py -3.3 -m timeit -n 1000000 -r 5 -v -s "def xdict(): return dict()" "xdict()"
raw times: 0.477 0.47 0.468 0.473 0.469
1000000 loops, best of 5: 0.468 usec per loop
$ py -3.3 -m timeit -n 1000000 -r 5 -v -s "def xdict(dict=dict):
return dict()" "xdict()"
raw times: 0.451 0.45 0.451 0.45 0.449
1000000 loops, best of 5: 0.449 usec per loop
$ py -3.3 -m timeit -n 1000000 -r 5 -v -s "def xdict(dict=lambda **kw:
kw): return dict()" "xdict()"
raw times: 0.433 0.434 0.435 0.435 0.431
1000000 loops, best of 5: 0.431 usec per loop
$ py -3.3 -m timeit -n 1000000 -r 5 -v -s "def xdict(dict=dict):
return {}" "xdict()"
raw times: 0.276 0.279 0.279 0.277 0.275
1000000 loops, best of 5: 0.275 usec per loop
And using non-empty dicts doesn't change much and the first one is
roughly the sum of the latter two (as expected):
C:\Users\lrekucki>py -3.3 -m timeit -n 1000000 -r 5 -v -s "def
xdict(dict=dict): return dict(a=1, b=2, c=3, d=4, e=5, f=6)" "xdict()"
raw times: 1.72 1.71 1.71 1.71 1.71
1000000 loops, best of 5: 1.71 usec per loop
C:\Users\lrekucki>py -3.3 -m timeit -n 1000000 -r 5 -v -s "def
xdict(dict=lambda **kw: kw): return dict(a=1, b=2, c=3, d=4, e=5,
f=6)" "xdict()"
raw times: 1.01 1.01 1.01 1.01 1.01
1000000 loops, best of 5: 1.01 usec per loop
C:\Users\lrekucki>py -3.3 -m timeit -n 1000000 -r 5 -v -s "def
xdict(dict=dict): return {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f':
6}" "xdict()"
raw times: 0.744 0.736 0.735 0.733 0.733
1000000 loops, best of 5: 0.733 usec per loop
I hope that this helps move python-dev's focus to some more useful discussion.
--
Łukasz Rekucki