%%HTML
<img src="https://pbs.twimg.com/media/EUN22kzXYAIxrtJ?format=jpg&name=900x900">
xD
Printing of recursive dictionaries and lists no longer causes a core dump.
What does this do?
some_numbers = range(11, 20)
list(map(lambda n: sum(map(int, str(n))), filter(lambda x: x % 2 == 0, some_numbers)))
Although map and filter are useful, in most cases list comprehension is more readable
[sum(int(d) for d in str(n)) for n in some_numbers if n % 2 == 0]
And the shortest version, because we all love python for brevity
[sum(map(int, str(n))) for n in some_numbers if n % 2 == 0]
%%HTML
<blockquote class="reddit-card" data-card-created="1587309184"><a href="https://www.reddit.com/r/ProgrammerHumor/comments/ftupjh/behind_every_oneliner_there_are_the_tears_of_many/">Behind every one-liner there are the tears of many</a> from <a href="http://www.reddit.com/r/ProgrammerHumor">r/ProgrammerHumor</a></blockquote>
<script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>
if False is not True:
raise AssertionError("Nope")
assert False is True, "Nope"
[i ** 2 for i in range(10) if i % 2 == 0]
numbers = []
for i in range(3):
for j in range(3):
numbers.append((i, j))
numbers
[(i, j) for i in range(3) for j in range(3)]
import random
[[random.choice(["O","X"," "]) for _ in range(3)] for _ in range(3)]
def f(*args, **kw):
# args is a tuple of positional args,
# kw is a dictionary of keyword args
print(locals())
a = [1, 2]
b = {"a": 1, "b": 3}
f(*a, **b)
f(1, 2, a=1, b=3)
Without kwargs:
import subprocess
subprocess.run("ls", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
subprocess.run("whoami", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
subprocess.run("pwd", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, check=True)
with kwargs:
run_kwargs = {"stdout": subprocess.PIPE, "stderr": subprocess.PIPE, "shell": True}
subprocess.run("ls", **run_kwargs)
subprocess.run("whoami", **run_kwargs)
subprocess.run("pwd", **run_kwargs, check=True)
list(zip("ab","cd"))
Very useful when you want to iterate over multiple sequences in one for loop
[a + b for a, b in zip("ab", "cd")]
numbers = [1, 2, 3, 4]
# iterate over pairs in the same sequence
[(a, b) for a, b in zip(numbers, numbers[1:])]
import atexit
@atexit.register
def goodbye():
print("You are now leaving the Python sector.")
It was already possible to define function inside another function, but the inner didn't have access to enclosing function scope
In Python 2.0, at any given time there are at most three namespaces used to look up variable names: local, module-level, and the built-in namespace
# module-scope
def f():
# local scope
pass
# builtin scope
__builtin__.print
def f():
x = 1
l = lambda: print(x) # NameError in python2.0
def g():
print(x) # NameError in python2.0
def g2(n):
if n > 0:
return n * g2(n-1) # NameError in python2.0
for i in range(3):
# not a scope
pass
i # i leaked to the enclosing scope
comprehensions don't leak variables to the enclosing scope
[unique_name for unique_name in range(3)]
unique_name
def f():
a_abc = 2
b_abc = 3
c = 4
print(locals())
return [locals()[name] for name in locals() if name.endswith("_abc")]
f()
%%HTML
<img src="https://media.makeameme.org/created/what-just-happened-5aaa59.jpg">
To understand why this happened we need to know how the iteration works in python:
l = [1,2,3]
it = iter(l)
while True:
try:
i = next(it)
print(i)
except StopIteration:
break
import inspect
class LoudIterable:
def __iter__(self):
print(inspect.currentframe())
return iter([1, 2])
x = [print(inspect.currentframe()) for i in LoudIterable()]
Basically, iter is called in a diferent scope than comprehension body
Very useful feature when it comes to generators
l = (print(i) for i in range(3))
non_iterable = 2
x = (i for i in non_iterable)
print("We won't reach this line, even though the iteration haven't started yet")
Btw, common scoping gotcha:
funcs = [lambda: print(i) for i in range(3)]
for f in funcs:
f()
When a name is used in a code block, it is resolved using the nearest enclosing scope.
x = 1
def f():
print(x)
f()
print(x)
x = 1
def f():
x = 2
print(x)
f()
print(x)
x = 1
def f():
x += 1
print(x)
f()
print(x)
x = 1
def f():
global x
x = x + 1
print(x)
f()
print(x)
x = 0
def outer():
x = 1
def f():
nonlocal x
x = x + 1
print(x)
f()
print(x)
outer()
print(x)
import warnings
def deprecated_function():
warnings.warn("will be removed tomorrow!", category=DeprecationWarning)
deprecated_function()
Python has a reference counting garbage collector
import sys
class A:
def hello(self):
print("hello")
a = A()
sys.getrefcount(a)
a_ref = a
sys.getrefcount(a)
del a
sys.getrefcount(a_ref)
import weakref
a_weakref = weakref.ref(a_ref)
a_weakref().hello()
sys.getrefcount(a_ref)
del a_ref
import gc
gc.collect() # force garbage collection
a_weakref() is None
def f():
if not hasattr(f, "_call_counter"):
f._call_counter = 1
f._call_counter +=1
f()
f._call_counter
f()
f._call_counter