Chapter 2. Branching Using Dictionaries

Functions are objects like everything else in Python, and a function’s name is an object reference that refers to the function. If we write a function’s name without parentheses, Python knows we mean the object reference, and we can pass such object references around just like any others. We can use this fact to replace if statements that have lots of elif clauses with a single function call.

In the examples accompanying the book, Programming in Python 3: A Complete Introduction to the Python Language,[*] is an interactive console program called dvds-dbm.py, that has the following menu:

[*] All the examples are available for download from www.qtrac.eu/py3book.html.

(A)dd  (E)dit  (L)ist  (R)emove  (I)mport e(X)port  (Q)uit


The program has a function that gets the user’s choice and which will return only a valid choice, in this case one of “a”, “e”, “l”, “r”, “i”, “x”, and “q”. Here are two equivalent code snippets for calling the relevant function based on the user’s choice:

image

The choice is held as a one-character string in the action variable, and the database to be used is held in the db variable. The import_() function has a trailing underscore to keep it distinct from the built-in import statement.

In the right-hand code snippet we create a dictionary whose keys are the valid menu choices, and whose values are function references. In the second statement we retrieve the function reference corresponding to the given action and call the function referred to using the call operator, (), and in this example, passing the db argument. Not only is the code on the right-hand side much shorter than the code on the left, but also it can scale (have far more dictionary items) without affecting its performance, unlike the left-hand code whose speed depends on how many elifs must be tested to find the appropriate function to call.

The convert-incidents.py program from the book’s examples uses this technique in its import_() method, as this extract from the method shows:

call = {(".aix", "dom"): self.import_xml_dom,
        (".aix", "etree"): self.import_xml_etree,
        (".aix", "sax"): self.import_xml_sax,
        (".ait", "manual"): self.import_text_manual,
        (".ait", "regex"): self.import_text_regex,
        (".aib", None): self.import_binary,
        (".aip", None): self.import_pickle}
result = call[extension, reader](filename)


The complete method is 13 lines long; the extension parameter is computed in the method, and the reader is passed in. The dictionary keys are 2-tuples, and the values are methods. If we had used if statements, the code would be 22 lines long, and would not scale as well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset