These are mainly for my own reference, but I thought that as they are useful to me they might enlighten others. These are presented in no particular order, and will certainly be added to over time.

The Zen of Python

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!

— Tim Peters

Available by typing import this in python, or python -c "import this" in a terminal.

Prefer functions to classes

While I generally always use classes and (hopefully) good object oriented design, there are always occasions when you should be writing a function not another class. A good rule is that if you havea class which is __init__ and a member function, it is just a function.

Use argparse

This is a library which parses command line arguments very well. It makes a useful help text and is easy to use.

An example.

#==============================================================================
def main():
    """
    Get argument, then pass it to WordPressToMarkdown
    """
    des = "This script converts wordpress.com html into markdown syntax."
    parser = argparse.ArgumentParser(description=des)
    parser.add_argument("wordpress_html")
    parser.add_argument(
        "-f",
        "--file",
        help="Read the WordPress.com html from a file",
        action="store_true"
        )

    args = parser.parse_args()
    converter = WordPressToMarkdown()
    source = args.wordpress_html
    if (args.file):
        with open(source, "r") as source_file:
            source = source_file.read()
    print(converter.convert(source))

The usage for this is as follows.

usage: WordPressToMarkdown.py [-h] [-f] wordpress_html

This script converts wordpress.com html into markdown syntax.

positional arguments:
  wordpress_html

optional arguments:
  -h, --help      show this help message and exit
  -f, --file      Read the WordPress.com html from a file

Put item in a dictionary or add to it if it exists

This is something I often find myself doing. I used to use code like this.

if (not key in dictionary):
    dictionary[key] = value
else:
    dictionary[key] += value

There is in fact a more elegant and pythonic way of doing this. Using the setdefault function. This returns the value if the key is in the dictionary, otherwise it puts the value in. Here is an example.

dictionary.setdefault(key, 0)
dictionary[key] += value

Adding callbacks in a loop

If you do.

for i in range(10):
    button = Button(command=lambda : func(i))

Then all the buttons will call func(9) the last value of i.

The solution to this problem is this.

for i in range(10):
    button = Button(command=lambda i=i: func(i))

This binds the current value of i when the button is made.

Swapping Values

In other languages:

temp = a;
a = b;
b = temp;

In Python:

b, a = a, b

Use unittest

These are the useful members of unittest.TestCase which you derive your test class from.

self.assertEqual(a, b)
self.assertNotEqual(a, b)
self.assertTrue(x)
self.assertFalse(x)
self.assertIs(a, b)
self.assertIsNot(a, b)
self.assertIsNone(x)
self.assertIsNotNone(x)
self.assertIn(a, b)
self.assertNotIn(a, b)
self.assertIsInstance(a, b)
self.assertNotIsInstance(a, b)
self.assertRaises(exception, callable, arguments)

All of these have a good error message built in but you can override them like.

self.assertEqual(a, b, "a is not equal to b")

Except assertRaises, as it would read it as an argument to the callable.

Use “”.join() not + for string concatenation

# this is good
new_string = "".join("A", " good ", "method for con", "caternating strings.")
# this is bad
new_string = "A" + " bad " + "method for con" + "caternating strings."

This is because python strings are immutable and with + or += you will use up much more memory for temporary strings than you need to.

Use the Google Style Guide

It is found here. Though I don’t follow it blindly and disagree with a few points.

Write docstrings

I find them easier to read, more idiomatic and more helpful than comments at the beginning of functions/classes. Comments should be used to help understanding of implementation.Here is a nice use.

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """Fetches rows from a Bigtable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by big_table.  Silly things may happen if
    other_silly_variable is not None.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table row
            to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args, and which does nothing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}

        If a key from the keys argument is missing from the dictionary,
        then that row was not found in the table.

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """
    # a comment on implementation

Docstring should contain these sort of things. (This is directly from the Google Style Guide.

Args:
List each parameter by name. A description should follow the name, and be separated by a colon and a space. If the description is too long to fit on a single 80-character line, use a hanging indent of 2 or 4 spaces (be consistent with the rest of the file).
The description should mention required type(s) and the meaning of the argument.

If a function accepts *foo (variable length argument lists) and/or **bar (arbitrary keyword arguments), they should be listed as *foo and **bar.

Returns: (or Yields: for generators)
Describe the type and semantics of the return value. If the function only returns None, this section is not required.

Raises:
List all exceptions that are relevant to the interface.

Tkinter

Setting Attributes

use widget[“attrib”] = value
rather than widget.config(atrib=value)


0 Responses to “Python Tips”



  1. Leave a Comment

What did you think?




Call Me
Endorse davidcorne on Coderwall

Categories

Copyright


© 2013 by David Corne.

Creative Commons License

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.