Note
All else in RAM is lost — if your code produces NO side-effects, it will generate only heat — only Brownian motion!
Q: What does this code do?
def parse_hosts_file(path):
with open(path) as f:
for line in f:
host = line.strip()
print(host)
def parse_hosts_file(path):
with open(path) as f:
for line in f:
host = line.strip()
print(host)
A: It returns None
# Servers
www1.example.com
www2.example.com
mq.example.com
# Admin machines
merry.example.com
pippin.example.com
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if line:
if not line.startswith('#'):
print(line)
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
print(line)
parse_hosts_file('good_hosts.txt')
requests.post(url, data={'allow': host})
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
print(line)
Note
The hostnames still need to be printed when called from the original location — but now the text needs to be POSTed to an API as well.
Q: How will we change our code?
One solution
from mock import patch
hosts = []
with patch('builtins.print', hosts.append):
parse_hosts_file('good_hosts.txt')
for host in hosts:
requests.post(url, data={'allow': host})
from io import StringIO
sio = StringIO()
with patch('sys.stdout', sio):
parse_hosts_file('hosts.txt')
for host in sio.getvalue().split():
requests.post(url, data={'allow': host})
Another solution
total_shares += s
if symbol == 'IBM':
ibm_shares += s
elif symbol == 'APPL':
apple_shares += s
if symbol == 'IBM':
ibm_shares += s
elif symbol == 'APPL':
apple_shares += s
elif symbol == 'GOOG':
google_shares += s
elif symbol == 'FB':
facebook_shares += s
any n
shares = {}
for ...:
shares[symbol] = shares.get(symbol, 0) + n
n=2
def parse_hosts_file(path, url=None):
...
if url is None:
print(host)
else:
data = {'allow': host}
requests.post(url, data=data)
Several “any n” solutions
def parse_hosts_file(path):
hosts = []
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
hosts.append(line)
return hosts
Note
But if there are billions of hosts, this can exhaust RAM, and offers high latency.
def parse_hosts_file(path, use_host):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
use_host(line)
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
yield line
Top-level glue code
for host in parse_hosts_file('hosts.txt'):
print(host)
# or
for host in parse_hosts_file('hosts.txt'):
requests.post(url, data={'allow': host})
for host in parse_hosts_file('hosts.txt'):
requests.post(url, data={'allow': host})
top ────────┐ ┌─────────
│ │
│↓ call │↑ return
│ │
subroutine └──print()──┘
top ────────┐ ┌──print()──
│ │
│ │ ↑
│ │
subroutine └───────┘
top ────────┐ ┌──requests.post(…)──
│ │
│ │
│ │
subroutine └───────┘
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
yield line
def parse_hosts_file(path):
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
yield line
# Simpler: let caller do the open()
def parse_hosts_file(f):
for line in f:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
yield line
# But, wait - it is no longer
# limited to working with files!
def parse_hosts(lines):
for line in lines:
line = line.strip()
if not line:
continue
if line.startswith('#'):
continue
yield line
top ────────┐ ┌─────────
│ │
│ │
│ │
subroutine └─open()──print()─┘
top ──open()──┐ ┌──print()──
│ │
↑ │ │ ↑
│ │
subroutine └───────────┘
All I/O now lives in top-level glue code
with open('hosts.txt') as f:
for host in parse_hosts(f):
print(host)
Note
Andrew Godwin
2013 blog post
— Andrew Godwin
2013 blog post
— Andrew Godwin
http://www.aeracode.org/2013/5/30/what-operation/ http://www.aeracode.org/2013/10/23/flat-pancake/
What is the user ID
for this username? ↘
DB
To which team does ↙
user 94914 belong? ↘
DB
Which other users ↙
belong to team 38135?
class UserStorage:
def get_user_by_username(username):
...
def get_team_by_user_id(username):
...
def get_members_by_team_id(username):
...
Your unit tests
Python is a dynamic language