#28909 closed Cleanup/optimization (fixed)
Use unpacking generalizations added in Python 3.5
Reported by: | Nick Pope | Owned by: | Nick Pope |
---|---|---|---|
Component: | Core (Other) | Version: | dev |
Severity: | Normal | Keywords: | unpacking |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Now that master is Python 3.5+ we can look to using unpacking generalizations for dict, list, set and tuple.
https://docs.python.org/3.5/whatsnew/3.5.html#whatsnew-pep-448
One benefit to this is that slow function/method calls can avoided and specific operations for unpacking are used instead:
$ python -c "import dis; dis.dis(\"d0 = {'a': 1}; d1 = {'b': 2}; x = {**d0, **d1}\")" 1 0 LOAD_CONST 0 ('a') 2 LOAD_CONST 1 (1) 4 BUILD_MAP 1 6 STORE_NAME 0 (d0) 8 LOAD_CONST 2 ('b') 10 LOAD_CONST 3 (2) 12 BUILD_MAP 1 14 STORE_NAME 1 (d1) 16 LOAD_NAME 0 (d0) 18 LOAD_NAME 1 (d1) 20 BUILD_MAP_UNPACK 2 22 STORE_NAME 2 (x) 24 LOAD_CONST 4 (None) 26 RETURN_VALUE $ python -c "import dis; dis.dis(\"d0 = {'a': 1}; d1 = {'b': 2}; x = dict(d0, **d1)\")" 1 0 LOAD_CONST 0 ('a') 2 LOAD_CONST 1 (1) 4 BUILD_MAP 1 6 STORE_NAME 0 (d0) 8 LOAD_CONST 2 ('b') 10 LOAD_CONST 3 (2) 12 BUILD_MAP 1 14 STORE_NAME 1 (d1) 16 LOAD_NAME 2 (dict) 18 LOAD_NAME 0 (d0) 20 BUILD_TUPLE 1 22 LOAD_NAME 1 (d1) 24 CALL_FUNCTION_EX 1 26 STORE_NAME 3 (x) 28 LOAD_CONST 4 (None) 30 RETURN_VALUE $ python -c "import dis; dis.dis(\"d0 = {'a': 1}; d1 = {'b': 2}; x = d0.copy(); x.update(d1)\")" 1 0 LOAD_CONST 0 ('a') 2 LOAD_CONST 1 (1) 4 BUILD_MAP 1 6 STORE_NAME 0 (d0) 8 LOAD_CONST 2 ('b') 10 LOAD_CONST 3 (2) 12 BUILD_MAP 1 14 STORE_NAME 1 (d1) 16 LOAD_NAME 0 (d0) 18 LOAD_ATTR 2 (copy) 20 CALL_FUNCTION 0 22 STORE_NAME 3 (x) 24 LOAD_NAME 3 (x) 26 LOAD_ATTR 4 (update) 28 LOAD_NAME 1 (d1) 30 CALL_FUNCTION 1 32 POP_TOP 34 LOAD_CONST 4 (None) 36 RETURN_VALUE $ python -m timeit "d0 = {'a': 1}; d1 = {'b': 2}; x = {**d0, **d1}" 1000000 loops, best of 3: 0.24 usec per loop $ python -m timeit "d0 = {'a': 1}; d1 = {'b': 2}; x = dict(d0, **d1)" 1000000 loops, best of 3: 0.39 usec per loop $ python -m timeit "d0 = {'a': 1}; d1 = {'b': 2}; x = d0.copy(); x.update(d1)" 1000000 loops, best of 3: 0.45 usec per loop
Obviously these are fairly contrived examples, and in many cases there can be multiple calls to methods such as dict.update()
or list.extend()
.
Here are examples of a number of changes that could be made:
# Unpack directly into initial definition: -d = {...} -d.update(extra) +d = {..., **extra} # Unpack instead of using dict() to combine (#1): -d = dict(original, **extra) +d = {**original, **extra} # Unpack instead of using dict() to combine (#2): -d = dict(original, ...) +d = {**original, ...} # Unpacking peforms a shallow copy like dict(): -d = dict(original) -d.update(extra) +d = {**original, **extra} # Unpacking peforms a shallow copy like dict.copy(): -d = original.copy() -d.update(extra) +d = {**original, **extra} # Unpacking peforms a shallow copy like copy.copy(): -import copy -d = copy.copy(original) -d.update(extra) +d = {**original, **extra} # More complex examples that become simple: -d = dict(original, ...) -d.update(extra or {}) +d = {**original, ... **(extra or {})} # Unpacking for sets also makes things simple: -s = {...} -s.update(extra) -s.update(override) +s = {..., *extra, *override} # Unpacking for lists also makes things simple: -l = [...] -l.extend(extra) -l.extend(override) +l = [..., *extra, *override]
Change History (5)
comment:1 by , 7 years ago
Component: | Uncategorized → Core (Other) |
---|---|
Triage Stage: | Unreviewed → Ready for checkin |
Note:
See TracTickets
for help on using tickets.
PR