Python Introduction

In this series I'll be looking at a few of the more interesting aspects of Python and bestowing upon you a wealth of knowledge that will help you write shorter, better code.

This set of guides assume a basic understanding of Python, you should ideally know how to start IDLE, how to run Python scripts from the Command Line and how to run an Interactive Python Shell, or "REPL."

When you see a code block below, and in subsequent articles, you might see some odd dots or arrows. These mark an example you should type right into Python and tinker about with to get a better understanding of what I'm talking about.

Anything preceeded by 3 arrows (>>>) or 3 dots (...) is what's being typed in- that's the prompt that Python gives you.

Anything without a prompt before it is what Python's responding back with.

If you don't see a prompt in a code block at all, don't worry about typing it into a REPL. It's just an example I'm giving!

Before we begin, there are a few things you should know:

Writing Code

When you first experiment with a new library or concept in Python it's a good idea to use the interactive shell. This is also known as a "REPL", which stands for Read Eval Print Loop. a REPL will Read your input, Evaulate it, Print the result, and then Loop back to reading the next input.

When you start IDLE, the Python IDE, you will be greeted with a REPL that lets you type in single lines of Python for evaluation. You can also start one by simply typing python in LXTerminal.

Using a REPL allows you to prod and poke at new things and figure out what they do. You can very easily explore Python this way, and avoid having to delve into docs.

Two very useful Python built-ins for this are dir and help. Dir will give you a directory of methods and variables available in a particular module or class:

pi@raspberry ~/piglow/library $ sudo python
>>> import piglow
>>> dir(piglow)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '_exit', '_le
gs', '_values', 'all', 'arm', 'arm1', 'arm2', 'arm3', 'atexit', 'auto_update', '
blue', 'clear', 'clear_on_exit', 'colour', 'colours', 'get', 'green', 'led', 'le
d1', 'led10', 'led11', 'led12', 'led13', 'led14', 'led15', 'led16', 'led17', 'le
d18', 'led2', 'led3', 'led4', 'led5', 'led6', 'led7', 'led8', 'led9', 'leg', 'le
g_bar', 'off', 'orange', 'red', 'ring', 'set', 'show', 'single', 'sn3218', 'spok
e', 'time', 'tween', 'white', 'yellow']
>>>

Or even the global namespace:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> my_var = 1
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'my_var']

And help will show you the documentation for one, as long as it's present in the library:

>>> help(set)
Help on function set in module __main__:

set(leds, value)
    Set one or more LEDs with one or more values

    Args:
    * leds - A single index, or list of indexes of the LEDs to set
    * values - A single value, or list of values to set

( press Q to quit help )

A Python shell also makes a great calculator:

>>> 10293 * 3
30879

Or a decimal to binary converter:

>>> bin(255)
'0b11111111'

Or a hex to deximal converter:

>>> 0x1c
28

Or a string length checker:

>>> len("How long is this string")
23

Or to solve maths problems involving Sailors, Monkeys and Coconuts! ( Don't use this if you don't like spoilers! )

>>> def coconuts(number):
...    for sailor in range(5):
...        if not number % 5 == 1:
...            return False
...        number -= int(number/5) + 1
...    return number % 5 == 0

( No, the monkey doesn't get a 6th coconut! )

Stylish Code

The Gold Standard for stylish, readable and consistently formatted Python code is known as the PEP 8 Style Guide. This style guide covers all the minutae of how to indent your Python code, how to format variable and class names, and more. If you don't want to read the above, you should at least remember to:

  • Indent by multiples of 4 spaces
  • Use capital words, and no breaks for class names: MyClass
  • Use all lowercase and underscores if necessary for function names: my_function
  • Use all caps for constants, and underscores if necessary: MY_CONSTANT = 1
  • Use a single leading underscore _my_fn to indicate a function should not be called directly by the user

Commenting Code

Should you use comments? Yes, but sparingly! The only thing worse than no comments is a meaningless or outright misleading comment.

Use comments only to shed light on difficult, strange or confusing concepts. In cases when your code is complicated enough that it needs several lines of comments to explain what it's doing, consider rewriting it.

A neccessary comment might be:

self.gpio_pwm.stop()

# Some gymnastics here to fix a bug ( in RPi.GPIO? )
# That occurs when trying to output(1) immediately
# after stopping the PWM

# A small delay is needed. Ugly, but it works
if blinking and value == 1:
    time.sleep(0.02)

GPIO.output(self.pin,value)

The above tells a developer exactly why this weird, apparently unecessary delay exists so they don't simply optimise it out and run into the same bug.

And an utterly pointless comment might be:

# Sleep a bit
time.sleep(0.0001)

And, finally, a somewhat questionable description of code that could perhaps be rewritten to be clearer:

# Play only once if loop is false
if loop == False and int(now / total) > 0:
    self._stop_buzzer()
    return False

The above is also not the complete picture! What on earth has int(now / total) > 0 got to do with loop == False? We just don't know.

Apologetic Comments

In the real world things are a little different. If you embark upon a career as a programmer and inherit or pass on code, you might eventually find yourself writing an apologetic comment.

An apologetic comment is what happens when you come across a spaghetti mess of code that takes you some time to understand, or when you produce code you know is bad but don't have time to refactor it. You'll write a comment that details everything you learned about the code, so the next person ( who may or may not be you ) doesn't have to spend time re-learning the same code.

In all cases the correct thing to do is to rewrite the code and make it clearer, but that may not be practical or even possible. A simple mistake in your rewrite could introduce a whole host of problems you could avoid by simply passing the problem on to the next programmer- or, more typically, yourself a few months from now when you have a moment to spare.

Documenting Code

Inline documentation is a different beast altogether. While the specific details of a function or method might change, very rarely will you change what arguments it accepts and what its expected behaviour is.

In fact, if your code is already in use somewhere it would be outright reckless to change the behaviour of a method. Documentation can help ensure that changes to the implementation don't result in changes to behaviour by explicitly stating how a function should behave so future developers have something to test against. The canonical solution to this very problem is test coverage. Tests explicitly check that functions do what they're supposed to do, but they're way beyond the scope of this introduction!

Python code can be documented with Docstrings. These are multi-line comments that Python's help function can understand.

A Docstring should look something like this:

def add_lists(list_a, list_b):
    '''Adds the values of two lists together, returns a list of results

    Arguments:
    * list_a - the first list of numbers
    * list_b - the second lists of numbers
    '''

These are useful not only to future developers of your code, but to the people using it too. What if we ran help on this imaginary method?

>>> help(add_lists)
Help on function add_lists in module __main__:

add_lists(list_a, list_b)
    Adds the values of two lists together, returns a list of results

    Arguments:
    * list_a - the first list of numbers
    * list_b - the second lists of numbers

Boom! We've now got self-documenting code that any Python user can get help on, right in the interactive shell.

That's all folks!

Search above to find more great tutorials and guides.

Plasma 2040

Swathe everything in rainbows with this all-in-one, USB-C powered controller for WS2812/Neopixel and APA102/Dotstar addressable LED strip.