General Points


  • __init__.py needs to contain something like:
  • __all__ = [
  • __name__ interpolates to the name of the module (python script name minus .py) when the modules (script) is being imported in another script. When it is being ran as a standalone script, __name__ interpolates to __main__ .  Therefore...
  • having the following code allows the script to be ran as a standalone script with whatever follows the if statement. E.g.
  • if __name__ == '__main__':
  • *args is a variable length list. I.e. info(message, *args): means info() accepts at least one parameter (message), plus any number of others.
    • args can be any string, it's the * which is important and it is just the convention to use args
    • when referencing and expanding to values, drop the *. E.g. args
    • when referencing as a handle (I.e. without expanding to the values) keep the *. E.g. *args
  • **kwargs is another variable length dictionary for key/value pairs. ** is the important syntax here
    • The same principle applies when referencing. I.e. drop a single * or keep both
  • __file__ is a special variable that expands to information about the actual script. E.g. if the script is called /home/me/my_script.py, os.path.abspath(__file__) will interpolate to /home/me/. See https://docs.python.org/2.7/library/os.path.html#os.path.abspath

Use the adapted type

A dict is not an ordered type. If you need an ordered dict, use a more advanced collection type like the ordered dict:

>>> from collections import OrderedDict
>>> d = OrderedDict({'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2})
>>> d
OrderedDict([('orange', 2), ('apple', 4), ('banana', 3), ('pear', 1)])

Careful about Mutable types and non-mutable types

A set is immutable, whereas a list is mutable:
>>> s = set([1,2])
>>> l = 1,2
>>> l.append(3)
>>> list(l)1, 2, 3
>>> s.append(3)
Traceback (most recent call last):
  File "", line 1, in
AttributeError: 'set' object has no attribute 'append'

A string is immutable. If you want to modify it, build another string:
>>> s = "hello"
>>> s.replace('ll', 'bb')
>>> s+"you"
>>> s'hello'

Base type are objects

It means that in python, classes are types (let’s understand it like that at first glance)
>>> a = 2
>>> isinstance(a, int)
>>> s = "a"
>>> dir(s)
['add', 'class', 'contains', 'delattr', 'dir', 'doc',
'eq', 'format', 'ge', 'getattribute', 'getitem',
'init', 'iter', 'le', 'len', 'lt', " rel="">'add', 'class', 'contains', 'delattr', 'dir', 'doc',
'eq', 'format', 'ge', 'getattribute', 'getitem',
'init', 'iter', 'le', 'len', 'lt', ]

s has methods. It’s an objects. The type of s is the int class

>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
>>> isinstance(d, dict)

Important But a base type doesn’t have attributes.

>>> a = 2
>>> a.a = 5
Traceback (most recent call last):
  File "", line 1, in
AttributeError: 'int' object has no attribute 'a'

If you want attributes in types you have to inherit from the base types:

>>> class A(int): pass
>>> a = A()
>>> a.a = 5

Difference between os.getenv(VAR) and os.environ(VAR)

os.environ will fail immediately if there is no value set for VAR
os.getenv will default VAR to none
os.getenv also allows or to be used. For example:

host = os.getenv(ENV_HOST_PROD) or ENV_HOST_DEV
user = os.environ[ENV_USERNAME]