Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It will also make your code drastically slower.


Slower yes, but not drastically:

    % python -m timeit '{"key": "value", "dr_nic": "The Comedian", "ttl": 42}'
    1000000 loops, best of 3: 0.296 usec per loop

    % python -m timeit 'dict(key="value", dr_nic="The Comedian", ttl=42)'
    1000000 loops, best of 3: 0.771 usec per loop
There are far better ways to make code faster than worrying about the extra fraction of a microsecond you're spending calling dict rather than using the literal syntax.


Slower than what alternative?


Slower than my_dict = { "foo": 1, "baz": 2 }

I was unaware that there was a difference in performance, but a quick timing check shows that it takes about twice as long to create a dictionary with 7 items using dict() than using {}.

It makes sense when I stop to think about what the code would have to do, though.


You're right; I'm seeing dict() with explicit kwargs taking 3 times as long as a literal. My unscientific and non-rigorous benchmarks tell me that the construction and unpacking of the kwargs in the dict() call are the cause of most of the slowdown.

With the time it takes to assign with a literal normalized to 1, I'm seeing dict(kwargs) (with kwargs created before the benchmark) take 2 and dict(key_1=val_1, key_2=val_2, etc.) take 3.


Unpacking kwargs is pretty much equivalent to building a dict. The major slowdown is 1) looking up dict and 2) calling a function:

    >>> def dict1():
    ...     {"a" : 1, "b" : 2}
    ... 
    >>> from dis import dis
    >>> dis(dict1)
      2           0 BUILD_MAP                2
                  3 LOAD_CONST               1 (1)
                  6 LOAD_CONST               2 ('a')
                  9 STORE_MAP           
                 10 LOAD_CONST               3 (2)
                 13 LOAD_CONST               4 ('b')
                 16 STORE_MAP           
                 17 POP_TOP             
                 18 LOAD_CONST               0 (None)
                 21 RETURN_VALUE        
    >>> def dict2():
    ...     dict(a=1, b=2)
    ... 
    >>> dis(dict2)
      2           0 LOAD_GLOBAL              0 (dict)
                  3 LOAD_CONST               1 ('a')
                  6 LOAD_CONST               2 (1)
                  9 LOAD_CONST               3 ('b')
                 12 LOAD_CONST               4 (2)
                 15 CALL_FUNCTION          512
                 18 POP_TOP             
                 19 LOAD_CONST               0 (None)
                 22 RETURN_VALUE        
Given that, I'd assume that the overhead doesn't grow as the dict grows.


As python runtimes/JITs get better and better, the literal version could get relatively faster, since static assertions can potentially more easily be made about it; whereas the global 'dict' could be replaced with anything, requiring much more sophistication.

Say you use a dict in a non-mutating manner, it is made up of string literals only, and you construct it within a loop; it could be able to be pulled out as an invariant, the same could be true of the function-call case, but potentially not as easily.


In optimizing a dynamic language, the problem of a symbol being replaced like this is no big deal; it's all but the expected norm, and inline caching ought to take care of it.

On invariant code motion: it tends not to be a big win because programmers usually move obvious big code out of loops explicitly. They do that because relying on a compiler optimization to do it is unpredictable; you may accidentally trigger a wall in your optimizer's ability to analyze your code as it grows more complex over time.

But we really are arguing over small potatoes here.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: