Skip to content

Instantly share code, notes, and snippets.

@victorwyee
Last active November 10, 2020 03:31
Show Gist options
  • Select an option

  • Save victorwyee/e1c02d234e8c1a14db7bc247d9f887ed to your computer and use it in GitHub Desktop.

Select an option

Save victorwyee/e1c02d234e8c1a14db7bc247d9f887ed to your computer and use it in GitHub Desktop.
# Don't do this:
for i in [0, 1, 2, 3, 4, 5]:
print(i**2)
# Do this:
# In Python 2, range returns a list.
# In Python 3, xrange is deprecated. range now returns a generator.
for i in range(6):
print(i**2)
# Don't do this
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print(colors[i])
# Do this
for color in colors:
print(color)
# Don't do this
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)-1, -1, -1):
print(colors[i])
# Do this
for color in reversed(colors):
print(color)
# Don't do this
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print(i, '-->', colors[i])
# Do this
for i, color in enumerate(colors):
print(i, '-->', colors[i])
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
# Don't do this
# "Every C programmer knows what to do"
n = min(len(names), len(colors))
for i in range(n):
print(names[i], '-->', colors[i])
# Goes back 50 years to Lisp
# In Python 2, zip returned an iterable.
# In Python 3, zip returns an iterator.
for name, color in zip(names, colors):
print(name, '-->', color)
# Follows the iterator pattern
# Renamed to zip in Python 3
for name, color in izip(names, colors):
print(name, '-->', color)
colors = ['red', 'green', 'blue', 'yellow']
for color in sorted(colors):
print(color)
for color in sorted(colors, reverse=True):
print(color)
colors = ['red', 'green', 'blue', 'yellow']
# Don't do this
# Traditional Way (Python 2 only)
# O(N log N) complexity
def compare_length(c1, c2):
if len(c1) < len(c2): return -1
if len(c1) > len(c2): return 1
return 0
print(sorted(colors, cmp=compare_length))
# Do this
# O(N) complexity
print(sorted(colors, key=len))
# Don't do this
def find(seq, target):
found = False
for i, value in enumerate(seq):
if value == tgt:
found = True
break
if not found:
return -1
return 1
# Do this
def find(seq, target):
for i, value in enumerate(seq):
if value == tgt:
break
else: # nobreak
return -1
return 1
# Don't do this
def find(seq, target):
found = False
for i, value in enumerate(seq):
if value == tgt:
found = True
break
if not found:
return -1
return 1
# Do this
def find(seq, target):
for i, value in enumerate(seq):
if value == tgt:
break
else: # nobreak
return -1
return 1
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k in d:
print(k)
for k in d.keys():
if k.startswith('r'):
del d[k]
for k in d:
print(k, '-->', d[k])
for k, v in d.items():
print(k, '-->', d[k])
d = ['matthew', 'rachel', 'raymond']
colors = ['red', 'green', 'blue']
d = dict(zip(names, colors))
d = dict(enumerate(names))
colors = ['red', 'green', 'red', 'blue', 'green', 'red']
# Simplest
d = {}
for color in colors:
if color not in d:
d[color] = 0
d[color] += 1
# Better
for color in colors:
d[color] = d.get(color, 0) + 1
# Best (or use Counter)
d = defaultdict(int)
for colors in colors:
d[color] += 1
names = ['raymond', 'racel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie']
# Simplest
d = {}
for name in names:
key = len(name)
if key not in d:
d[key] = []
d[key].append(name)
# Old idiom
d = {}
for name in names:
key = len(name)
d.setdefault(key, []).append(name)
# Modern idiom
d = defaultdict(list)
for name in names:
key = len(name)
d[key].append(name)
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
while d:
key, value = d.popitem()
print(key, '-->', value)
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args([])
command_line_args = {k:v for k, v in vars(namespace).items() if v}
# Works
d = defaults.copy()
d.update(os.environ)
d.update(command_line_args)
# Better
d = ChainMap(command_line_args, os.environ, defaults)
doctest.testmod() # used to return (0, 4)
doctest.testmod() # TestResults(failed=0, attempted=4)
TestResults = namedtuple('TestResults', ['failed', 'attempted'])
p = 'Raymond', 'Hettinger', 0x30, '[email protected]'
# Don't do this
fname = p[0]
lname = p[1]
age = p[2]
email = p[3]
# Do this (more readable, faster)
fname, lname, age, email = p
# Don't do this
def fibonacci(n):
x = 0
y = 1
for i in range(n):
print(x)
t = y
y = x + y
x = t
# Do this (tuple unpacking)
def fibonacci(n):
x, y = 0, 1
for i in range(n):
print(x)
x, y = y, x+y
# Don't do this (incorrect)
x = x + dx*t
y = y + dy*t
# gets computed with new x and y, rather than old x and y
dx = influence(m, x, y, dx, dy, partial='x')
dy = influence(m, x, y, dx, dy, partial='y')
# Don't do this (works, but requires temporary variables)
tmp_x = x + dx*t
tmp_y = y + dy*t
tmp_dx = influence(m, x, y, dx, dy, partial='x')
tmp_dy = influence(m, x, y, dx, dy, partial='y')
x = tmp_x
y = tmp_y
dx = tmp_dx
dy = tmp_dy
# Do this
# calculations on the right are all done with the old values
x, y, dx, dy = (x + dx*t,
y + dy*t,
influence(m, x, y, dx, dy, partial='x'),
influence(m, x, y, dx, dy, partial='y'))
names = ['raymond', 'rachel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie']
# Don't do this! This is quadratric behavior
s = names[0]
for name in names[1:]:
s += ', ' + name
print(s)
# Do this
', '.join(names)
names = ['raymond', 'rachel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie']
# Don't do this (wrong data structure!)
del names[0]
names.pop(0)
names.insert(0, 'mark')
# Do this
names = deque(['raymond', 'rachel', 'matthew', 'roger',
'betty', 'melissa', 'judith', 'charlie'])
del names[0]
names.popleft()
names.appendleft('mark')
# Instead of this
def web_lookup(url, saved={}):
# Administrative Logic
if url in saved:
return saved[url]
# Business Logic
page = urllib.urlopen(url).read()
saved[url] = page
return page
# Do this
@cache
def web_lookup(url):
page = urllib.urlopen(url).read()
# LRU cache implementation
def cache(func):
saved = {}
@wraps(funct)
def newfunc(*args):
if args in saved:
return newfunc(*args)
result = func(*args)
saved[args] = result
return result
return newfunc
# Works
old_context = getcontext().copy()
getcontext().prec = 50
print Decimal(355) / Decimal(113)
setcontext(old_context)
# Better
with localcontext(Context(prec=50)):
print Decimal(355) / Decimal(113)
f = open('data.txt')
try:
data = f.read()
finally:
f.close()
with open('data.txt') as f:
data = f.read()
# Make a lock
lock = threading.Lock()
# Old-way to use a lock
lock.acquire()
try:
print('Critical section 1')
print('Critical section 2')
finally:
lock.release()
# New way to use a lock
with lock:
print('Critical section 1')
print('Critical section 2')
# Correct but irritiating
try:
os.remove('somefile.tmp')
except OSError:
pass
# Better
with ignored(OSError):
os.remove('somefile.tmp')
# Implemented in v3.4.
@contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
pass
# Correct but not fun
with open('help.txt', 'w') as f:
oldstdout = sys.stdout
sys.stdout = f
try:
help(pow)
finally:
sys.stdout = oldstdout
# Better
with open('help.txt', 'w') as f:
with redirect_stdout(f):
help(pow)
# Implemented in v3.4 (?)
@contextmanager
def redirect_stdout(fileobj):
oldstdout = sys.stdout
sys.stdout = fileobj
try:
yield fileobj
finally:
sys.stdout = oldstdout
# One way to get sum of squares up to 10
result = []
for i in range(10):
s = i ** 2
result.append(s)
print(sum(result))
# Better way
sum([i**2 for i in range(10)])
# Even better way
sum(i**2 for i in range(10))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment