I have found an interesting performance optimization. Instead of using all()
:
def matches(self, item):
return all(c.applies(item) for c in self.conditions)
I have profiled that it's faster when a loop is used instead:
def matches(self, item):
for condition in self.conditions:
if not condition.applies(item):
return False
return True
With all()
the profiler shows 1160 additional <genexpr>
calls:
4608 function calls (4600 primitive calls) in 0.015 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
580 0.002 0.000 0.008 0.000 rule.py:23(matches)
1160 0.002 0.000 0.005 0.000 rule.py:28(<genexpr>)
With the for
loop, there are no <genexpr>
calls:
2867 function calls (2859 primitive calls) in 0.012 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
580 0.002 0.000 0.006 0.000 rule.py:23(matches)
My question is where does the difference come from? My first though was that all
evaluates all conditions, but that's not the case:
def foo():
print('foo')
return False
all(foo() for _ in range(1000))
foo