Writing Better Python
Writing Better Python#
Whenever you build something big, it usually gets messy. Python has some tools to help
Pep#
pep
stands for python enhancement proposal.
Anyone can submit a pep and they contain a single idea to implement in python
Important peps#
pep8 - how python code should look (don’t live by the rule, it is for preferences)
Avoid single letter variable names as this causes problems with the python debugger
You can use flake8 <script>
to check pep8 rules
pep20 - the zen of python
>>> import this
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!
Coding should be pleasant
Docstring#
A docstring
is a string at the beginning of a class, method or function that documents what that bit of code does
You should never have to read the source code to find out what a library does, that is the job of documentation
Enclosed in 3 quote marks (triplequotes)..doc.py
def does_something(my_var):
"""Takes one argument and does something based on the type
If arg is a string, returns arg * 3
If arg is a int or float, returns arg + 10
"""
....
then check help
help(doc.does_something)
returns the info
Better to use them as docstring and not comments, use #
for comments
Logging#
import logging
logging.info("You won't see this")
logging.warn("Oh no")
logger.info("You are %s", username)
It is better to log through a logger, not directly through the package:
logger = logging.getLogger(__name__)
logger.info('Hello')
Logging Exceptions#
Use logger.exception(...)
try:
dangerous_code()
except Exception:
logger.exception("Something bad happened.")
If you don’t want to log at the ERROR
level:
logger.info("Something slightly bad happened.", exc_info=True)
Logging Setup#
Only setup logging, filtering and verbosity in your main program
logging.basicConfig(level=logging.DEBUG)
Some old packages use camelCase.
logging.basicConfig(filename='game.log',level=logging.DEBUG)
logging.getLogger("some_library").setLevel(logging.WARNING)
- Now logs into filename (relative)
- Level specifies what logging to pay attention to
Logging Levels#
CRITICAL
ERROR
WARNING
- Keep track of questionable thingsINFO
- MonitoringDEBUG
- Info about running of appNOTSET
Also remember to log errors in the Except
block
Sources#
Debugging#
Track the state of variables at any given time
You can actually go inside the script and see the state of variables
You can use the Python Debugger
import pdb
To set a breakpoint / trace, use:
pdb.set_trace()
$ python ar.py
> /Users/surfer190/projects/object-oriented-python/test/ar.py(7)<module>()
-> del my_list[3]
(Pdb)
The 7
and next line tells us the line and code that will be run
It works just like python shell and you can inspect variables
Commands#
- Use
next
orn
to run the next line q
- quitc
- continue running as normal
Important to remove pdb when you are done
Most of the time you wil use:
import pdb;pdb.set_trace()
The only time you can use a ;
in python