That's a technique called "hoisting" or "Loop-invariant code motion". In essence you do an operation that is executed multiple times but always returns the same value outside the loop instead of in the loop body.
In this case the loop would repeatedly lookup the add attribute of your seen set and create a "bound method". That's actually pretty fast but still an operation that is performed several times inside a loop and always gives the same result. So you can look up the attribute (in this case the bound method) once and store it in a variable to gain some performance.
Note that while this provides a speed-up it's by no means "much". I removed the second branch for this timing to make the code shorter:
from itertools import filterfalse
def unique_everseen(iterable):
seen = set()
seen_add = seen.add
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
def unique_everseen_without(iterable):
seen = set()
for element in filterfalse(seen.__contains__, iterable):
seen.add(element)
yield element
Some exemplaric timings:
# no duplicates
a = list(range(10000))
%timeit list(unique_everseen(a))
# 5.73 ms ± 279 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(unique_everseen_without(a))
# 6.81 ms ± 396 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# some duplicates
import random
a = [random.randint(0, 100) for _ in range(10000)]
%timeit list(unique_everseen(a))
# 1.64 ms ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit list(unique_everseen_without(a))
# 1.66 ms ± 16.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# only duplicates
a = [1]*10000
%timeit list(unique_everseen(a))
# 1.64 ms ± 78.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit list(unique_everseen_without(a))
# 1.63 ms ± 24.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
So while you get ~10% speedup in the no duplicates case it's actually almost useless in case you got lots of duplicates.
Actually this recipe shows another example of "hoisting", more specifically the filterfalse(seen.__contains__, iterable). This looks up the __contains__ method of your seen set once and repeatedly calls it inside the filterfalse.
Maybe the take-away should be: Hoisting method lookups is a micro-optimization. It reduces the constant factor of your loop. The speedup may be worth it in certain operations but personally I think it should be used sparingly and only in combination with profiling/benchmarking.