Skip to content

Instantly share code, notes, and snippets.

@joshschmelzle
Last active December 24, 2019 19:51
Show Gist options
  • Save joshschmelzle/0beb0956ba3e30018f580132cfb531a7 to your computer and use it in GitHub Desktop.
Save joshschmelzle/0beb0956ba3e30018f580132cfb531a7 to your computer and use it in GitHub Desktop.
python-notes-and-cheatsheet.md

https://youtu.be/skYBOXE02OQ

The Zen of Python: >>> import this

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

code style

use a program to format your code. have beef with the program, not tabs vs spaces.

black

python -m pip install black

flake8

python3 -m pip install flake8 flake8-2020 flake8-alfred flake8-fixme flake8-eradicate flake8-comprehensions flake8-variables-names flake8-builtins flake8-bugbear flake8-broken-line flake8-import-order flake8-tidy-imports flake8-type-annotations flake8-annotations-coverage

profiling

cProfile

Python includes a profiler called cProfile. It not only gives the total running time, but also times each function separately, and tells you how many times each function was called, making it easy to determine where you should make optimizations.

You can call it from within your code, or from the interpreter, like this:

import cProfile
cProfile.run('foo()')

Even more usefully, you can invoke the cProfile when running a script:

python -m cProfile myscript.py

pycallgraph

After a pip install pycallgraph (python -m pip install pycallgraph) and installing GraphViz you can run it from the command line:

pycallgraph graphviz -- ./mypythonscript.py

Or, you can profile particular parts of your code:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

Either of these will generate a pycallgraph.png

pip (package manager for Python packages)

pip install <package>
pip uninstall <package>

or (perhaps the preferred method)

python -m pip install <package>
python -m pip uninstall <package>

list installed packages

pip freeze
pip list

grep like search for installed packages

pip freeze | findstr flake

is and == usage or object value vs object identity

@jldiaz

If you want to check if two variables point to the same data, use is. If you want to check if the data pointed is equal, use ==.

Comparing values, use ==, if you want to compare if two objects are the same, use is. Note! Be aware of small integer caching. [-5] [-4] [...] [255] [256] are cached.

In [37]: n = 300

In [38]: m = 300

In [39]: n == m  # are the values of n and m equal?
Out[39]: True

In [40]: n is m  # are the objects the same?
Out[40]: False

In [41]: id(n)
Out[41]: 2471498708880

In [42]: id(m)
Out[42]: 2471498710576

In [43]: id(n) == id(m)
Out[43]: False

pythonic exceptions

contextlib.suppress(): a context manager to suppress specified exceptions. requires Python version >= 3.4.

contextlib.suppress.__doc__: Return a context manager that suppresses any of the specified exceptions if they occur in the body of a with statement and then resumes execution with the first statement following the end of the with statement.

import contextlib

with contextlib.suppress(json.decoder.JSONDecodeError):
    names = json.load(fp)

rather than / equivalent to

try:
    names = json.load(fp)
except json.decoder.JSONDecodeError as error:
    pass

comparing string formatting performance with timeit

"old-school" string formatting:

  • %-formatting
  • str.format()

new and improved way of string formatting

  • f-strings. f"", +simple syntax, +multiline, +speed

ex1

In [1]: import timeit

In [2]: timeit.timeit("""name = "Eric"
   ...: age = 74
   ...: '%s is %s.' % (name, age)""", number = 10000)
Out[2]: 0.002395399999997494

In [3]: timeit.timeit("""name = "Eric"
   ...: age = 74
   ...: '{} is {}.'.format(name, age)""", number = 10000)
Out[3]: 0.002659100000002468

In [4]: timeit.timeit("""name = "Eric"
   ...: age = 74
   ...: f'{name} is {age}.'""", number = 10000)
Out[4]: 0.0013457999999957337

ex2

In [6]: timeit.timeit("""interface = "wlan0"
   ...: channel = 165
   ...: 'interface %s on %s' % (interface, channel)""", number = 100000)
Out[6]: 0.030520099999989725

In [8]: timeit.timeit("""interface = "wlan0"
   ...: channel = 165
   ...: 'interface {} on {}'.format(interface, channel)""", number = 100000)
Out[8]: 0.036720299999956296

In [10]: timeit.timeit("""interface = "wlan0"
    ...: channel = 165
    ...: f'interface {interface} on {channel}'""", number = 100000)
Out[10]: 0.01480360000005021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment