Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Closed
Description
Right now the implementation ofMessage.__contains__ looks like this:
Lines 450 to 451 in2f2fa03
| def__contains__(self,name): | |
| returnname.lower()in [k.lower()fork,vinself._headers] |
There are several problems here:
- We build intermediate structure (
listin this case) - We use
listforinoperation, which is slow
The fastest way to do check if actually have this item is simply by:
def__contains__(self,name):name_lower=name.lower()fork,vinself._headers:ifname_lower==k.lower():returnTruereturnFalse
We do not create any intermediate lists / sets. And we even don't iterate longer than needed.
This change makesin check twice as fast.
Microbenchmark
Before
» pyperf timeit --setup 'import email; m = email.message_from_file(open("Lib/test/test_email/data/msg_01.txt"))' '"from" in m'.....................Mean +- std dev: 1.40 us +- 0.14 uspyperf timeit --setup 'import email; m = email.message_from_file(open("Lib/test/test_email/data/msg_01.txt"))' '"missing" in m'.....................Mean +- std dev: 1.42 us +- 0.06 usAfter
» pyperf timeit --setup 'import email; m = email.message_from_file(open("Lib/test/test_email/data/msg_01.txt"))' '"missing" in m'.....................Mean +- std dev: 904 ns +- 55 ns» pyperf timeit --setup 'import email; m = email.message_from_file(open("Lib/test/test_email/data/msg_01.txt"))' '"from" in m'.....................Mean +- std dev: 715 ns +- 24 nsThe second case is now twice as fast.
It probably also consumes less memory now, but I don't think it is very significant.
Importance
SinceEmailMessage (a subclass ofMessage) is quite widely used by users and 3rd party libs, I think it is important to be included.
And since the patch is quite simple and pure-python, I think the risks are very low.