One micro optimization can be done in the current no-op code is to avoid
assigning the empty list to a variable before returning it, which is less
operations in the Python virtual machine, for example:
{{{
In [5]: import dis
In [6]: def foo1():
...: responses = []
...: if True:
...: return responses
...:
In [7]: dis.dis(foo1)
2 0 BUILD_LIST 0
3 STORE_FAST 0 (responses)
3 6 LOAD_GLOBAL 0 (True)
9 POP_JUMP_IF_FALSE 16
4 12 LOAD_FAST 0 (responses)
15 RETURN_VALUE
>> 16 LOAD_CONST 0 (None)
19 RETURN_VALUE
In [8]: def foo2():
...: if True:
...: return []
...:
In [9]: dis.dis(foo2)
2 0 LOAD_GLOBAL 0 (True)
3 POP_JUMP_IF_FALSE 10
3 6 BUILD_LIST 0
9 RETURN_VALUE
>> 10 LOAD_CONST 0 (None)
13 RETURN_VALUE
}}}
Timing the two above example functions gives:
{{{
In [13]: %timeit foo1()
10000000 loops, best of 3: 160 ns per loop
In [14]: %timeit foo2()
10000000 loops, best of 3: 121 ns per loop
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27513>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* owner: nobody => Adam Chainz
* status: new => assigned
* has_patch: 0 => 1
Comment:
https://github.com/django/django/pull/7581
--
Ticket URL: <https://code.djangoproject.com/ticket/27513#comment:1>
* cc: me@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/27513#comment:2>
* version: 1.10 => master
* stage: Unreviewed => Ready for checkin
Comment:
LGTM
--
Ticket URL: <https://code.djangoproject.com/ticket/27513#comment:3>
Comment (by Adam Chainz):
`send()` with receivers can be optimized too with a list comprehension,
avoiding temp var `response` and method calls on `responses`:
{{{
In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def before(self, sender, **named):
for receiver in self._live_receivers(sender):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
return responses
def after(self, sender, **named):
return [
(receiver, receiver(signal=self, sender=sender, **named))
for receiver in self._live_receivers(sender)
]
:<EOF>
In [3]: dis.dis(before)
2 0 SETUP_LOOP 66 (to 69)
3 LOAD_FAST 0 (self)
6 LOAD_ATTR 0 (_live_receivers)
9 LOAD_FAST 1 (sender)
12 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
15 GET_ITER
>> 16 FOR_ITER 49 (to 68)
19 STORE_FAST 3 (receiver)
3 22 LOAD_FAST 3 (receiver)
25 LOAD_CONST 1 ('signal')
28 LOAD_FAST 0 (self)
31 LOAD_CONST 2 ('sender')
34 LOAD_FAST 1 (sender)
37 LOAD_FAST 2 (named)
40 CALL_FUNCTION_KW 512 (0 positional, 2 keyword pair)
43 STORE_FAST 4 (response)
4 46 LOAD_GLOBAL 1 (responses)
49 LOAD_ATTR 2 (append)
52 LOAD_FAST 3 (receiver)
55 LOAD_FAST 4 (response)
58 BUILD_TUPLE 2
61 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
64 POP_TOP
65 JUMP_ABSOLUTE 16
>> 68 POP_BLOCK
5 >> 69 LOAD_GLOBAL 1 (responses)
72 RETURN_VALUE
In [4]: dis.dis(after)
10 0 LOAD_CLOSURE 0 (named)
3 LOAD_CLOSURE 1 (self)
6 LOAD_CLOSURE 2 (sender)
9 BUILD_TUPLE 3
12 LOAD_CONST 1 (<code object <listcomp> at
0x1068b5930, file "<ipython-input-1-cece5b56e5de>", line 10>)
15 LOAD_CONST 2 ('after.<locals>.<listcomp>')
18 MAKE_CLOSURE 0
11 21 LOAD_DEREF 1 (self)
24 LOAD_ATTR 0 (_live_receivers)
27 LOAD_DEREF 2 (sender)
30 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
33 GET_ITER
34 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
37 RETURN_VALUE
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27513#comment:4>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"22a60f8d0b331bf06c066ccba4eea5bb5e4ac9f2" 22a60f8d]:
{{{
#!CommitTicketReference repository=""
revision="22a60f8d0b331bf06c066ccba4eea5bb5e4ac9f2"
Fixed #27513 -- Made Signal.send()/send_robust() a tiny bit faster.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27513#comment:5>