Overall this looks pretty good, but there are some places where you can write more idiomatic Python. Some general comments:
More docstrings and comments would be nice. For example: what is a “domestic” URL, and why does it match com/net? Explain why the code is written this way – it will make things much easier if you have to debug/modify a program later.
Using single letter variable names is a bad habit. It’s better to use words, because they’re more descriptive and make the program easier to read. (They’re also easier to grep for later!)
The Python convention for variable names is
dromedaryCase. (The exception is class names, which are
Now some specific comments about your Python style:
str as a variable name; this is the name of a builtin function. Overriding the names of the builtin functions is a bad practice, because it will cause all sorts of bugs later.
To avoid excessive indentation, I’d combine the two if statements at the end of listDomains into a single line:
if is_valid(my_str) and is_domestic(get_domain(my_str)):
Rather than doing
if match: return True; else: return False in isValid and isDomestic, you can just do
return match. That’s shorter, easier to read and more idiomatic.
In getDomain(), you should explain the format of the line that you’re expecting, so that I know why you’re taking the element in index 1.
In makeHostsFile, rather than having explicit open() and close() calls, the Python idiom is to use a
with open('hosts', 'w') as f:
for domain in domains:
Note also that I’ve used new-style string formatting rather than string concatenation; this is the preferred way to do this sort of construction.
I would extend the makeHostsFile function to take an optional path to the hosts file, so that this code is more portable.
Rather than doing your program at top-level, wrap it in a main() function and call as follows:
hosts_file = 'C:/Windows/System32/drivers/etc/hosts'
if __name__ == '__main__':
The code inside main() is only executed if the script is run directly, but if you import this file from another program, it will be ignored. That makes it easier to reuse this code, because there aren’t any funny side-effects from importing it.
In terms of speed, the regexes seem pretty simple. Is there any reason you couldn’t just do
return ('0.0.0.0' not in line) and ('127.0.0.1' not in line)
return line.endswith('.com') or line.endswith('.net')
which feels like it would probably be a lot faster?