- roadmap
- pep8
- Project Folder Org: ? https://docs.python-guide.org/writing/structure/
Decorators
Decorator == function wrapper. For module-level functions these are equivalent sugar:
import time
def time_it(func):
def now_ms():
return time.time() * 1000
def inner():
start = now_ms()
ret = func()
end = now_ms()
print("perf cost:", end-start, inner)
return ret
return inner
# form A: use decorators
@time_it
def final_func_name():
print("hello world")
# form B: underlying operation
final_func_name = time_it(lambda: print("hello other world"))
Later, see also functools.wraps
List Comprehensions
new_list = [expression for formal_arg_iterator_name in iterable]
# so...
numbers = [1, 2, 3, 4, 5]
squared_numbers = [n**2 for n in numbers]
# squared_numbers will be [1, 4, 9, 16, 25]
squares = list(map(lambda x: x**2, range(10)))
# IS
squares = []
for x in range(10):
squares.append(x**2)
# IS
squares = [x**2 for x in range(10)]
Filtering
basic_syntax = [result_expression for iter_arg in iterable]
filter_syntx = [result_expression for iter_arg in iterable if cond_exp]
numbers = [1, 2, 3, 4, 5]
squared_evens = [n**2 for n in numbers if n%2 == 0]
# [4, 16]
As python's trinary conditional expression is "happy_exp if cond_exp else sad_exp", the result expression can also have a fork:
trunc_to_even = [n-1 if n%2 else n for n in numbers]
# [0, 2, 2, 4, 4]
Nested List Comps, or How We Blew Readability in the Name of Readability
- more readable: https://stackoverflow.com/questions/18072759
- read later: A C-head goes into depth to make it click: https://rhodesmill.org/brandon/2009/nested-comprehensions/
- 2nd example at official is a good walkthrough of for-for syntax.
- why I'd avoid: https://www.geeksforgeeks.org/python/nested-list-comprehensions-in-python/
- discussion: https://www.reddit.com/r/Python/comments/wi00ih/does_anybody_else_just_not_like_the_syntax_for/
Ah! a single listcomp can have multiple for-iter clauses. (and apparently more than one if-filter clauses??)
out = []
for x in range(1, 10):
for y in range(2,4):
out.append(x+y)
# becomes
out = [x+y for x in range(1,10) for y in range(2,4)]
Variadic Args
def show_args(func):
def inner(*args, **kwargs):
print("args:", args)
print("kwargs:", kwargs)
return func(*args, **kwargs)
return inner
@show_args
def do_stuff(*args, **kwargs):
print("my args:", args)
print("my kwargs:", kwargs)
do_stuff("foo", "bar", a="b", c="d")
results: args is a tuple, kwargs is a map ({'a': 'b', 'c': 'd'}
)
String Interpolation
message = "hello world"
print(f"Message was: {message}")
or was this the pep8 direction? print("My arguments are: {0}, {1}".format(arg1,arg2))
Lambdas
- Py lambdas only have expression mode; there is no anon body-form.
- (why? because) "the complexity of any proposed solution for this puzzle is immense, to me: it requires the parser (or more precisely, the lexer) to be able to switch back and forth between indent-sensitive and indent-insensitive modes, keeping a stack of previous modes and indentation level. Technically that can all be solved (there's already a stack of indentation levels that could be generalized). But none of that takes away my gut feeling that it is all an elaborate Rube Goldberg contraption." --G
const js_classic = function() {};
const js_fat_arrow_body = () => {console.log("hello")};
const js_fat_arrow_expr = () => console.log("hello");
py_arity0 = lambda: print("hello")
py_arity1 = lambda x: print("hello", x)
py_arityN = lambda x, y, z: print("hello", x, y, z)
Force a closure using an argument with a default value:
x = 42
example = lambda arg=x: return f"meaning of life: {arg}"
While the above is simpler as example = lambda: f"meaning of life: {x}"
formal-arg closures are required reading for this list comp: li = [lambda arg=x: arg * 10 for x in range(1, 5)]
which is "create a arity 0 function that returns i*10 for each i in 1 to 5"
(src doc: li = [lambda arg=x: arg * 10 for x in range(1, 5)]
)
Tuples
Was it this? force a len(1) tuple with (val,)
show asm-like bytecode
import dis
add = lambda x, y: x + y
dis.dis(add)