Instead of `open(filename, 'r+b').read().split('\n')` you can use `for line in open(filename):`, which avoids loading large files into memory. (small gotcha: `line` will contain the newline character(s) which can be stripped via e.g. `rstrip`)
You can also drop the square brackets from calls to methods that take an iterable e.g. `any`/`all`, `set`, and `join`. So `join([...])` becomes simply `join(...)`. Python will use a generator expressions instead of constructing and passing a new list list. To quote PEP 289: "generator expressions [are] a high performance, memory efficient generalization of list comprehensions"
These can really make a difference with big files/lists, but are a good habit in any case. I hope it helps in the future!