Let's now spend some time discussing the tips and tricks that will help improve the performance of our Python program. In a normal case scenario of GUI programming, this generally involves speeding up sections of program that contribute to improving the overall user experience.
Program optimization is often obsessively taken as an exercise in reducing code execution time. For programs where timing is a crucial factor, this obsession is genuine. However, if you are developing a simple GUI application, a correct and consistent user experience is generally more important than mere fast user experience.
Trying to optimize a code even before it is functional is premature optimization and should be avoided. However, a GUI program with correct but considerably long response time probably needs to be optimized, and this is the subject of discussion of the following sections.
Selecting the right data structure can have a profound impact on the performance of a program. If your program is to spend considerable time on lookups, use a dictionary, if feasible. When all you need is to traverse over a collection, prefer to choose a list over dictionaries, because dictionaries take more space.
When your data is immutable, prefer to choose tuples over lists, because tuples can be traversed faster than lists.
The way you select variables in your program can considerably affect the speed of the execution of your program. For instance, if you do not need to change the content or attributes of a widget after its instantiation, do not create a class-wide instance of the widget.
For example, if a Label widget is to remain static, use Label(root, text='Name').pack(side=LEFT)
, instead of using the following snippet:
self.mylabel = Label(root, text='Name') self.mylabel.pack(side=LEFT)
Similarly, do not create local variables if you are not going to use them more than once. For example, use mylabel.config (text= event.keysym)
instead of first creating a local variable key
and then using it only once:
key = event.keysym mylabel.config (text=key)
If the local variable is to be used more than once, it may make sense to create a local variable.
Now here is a small caveat. In order to concentrate on illustrating core Tkinter concepts, we have deliberately ignored the clean exception handling in all our examples in this book.
We have implemented a "catch all errors" exception using simple try-except blocks in most of our projects. However, when programming your applications, you would ideally want to be as specific as possible about the exception you want to handle.
Python follows the EAFP (easier to ask for forgiveness than permission) style of coding, as opposed to the LBYL (look before you leap) style followed by most other programming languages.
Thus, using exception handling similar to the following one is normally cleaner in Python than checking conditions using the if-then block:
try: doSomethingNormal() except SomethingWrong: doSomethingElse()
An example of an if-then block is shown in the following code snippet:
if SomethingWrong: doSomethingElse() else: doSomethingNormal()
Python provides two built-in functions named filter
and map
to manipulate lists directly, rather than having to directly iterate over each item in the list. The filter
, map
, and reduce
functions are faster than using loops, because a lot of the work is done by the underlying code written in C.
filter(function, list)
function returns a list (iterators in Python 3.x) that contains all the items for which the function returns a true value. For example:print filter(lambda num: num>6, range(1,10))# prints [7, 8, 9]
This is faster than running a conditional if-then check against the list.
map(func, list)
function applies func
to each item in the list and returns the values in a new list (returns iterators instead of lists in Python 3.x). For example:print map(lambda num: num+5, range(1,5)) #prints [6, 7, 8, 9]
This again is faster than running the list through a loop, adding 5
to each element.
Profiling involves generating detailed statistics to show how often and for how long various routines of a program execute. This helps is isolating offending parts of a program, and those parts probably need redesigning.
Python 2.7.x provides a built-in module named cProfile
, which enables generation of detailed statistics about a program. The module gives details such as the total program-running time, time taken to run each function, and the number of times each function is called. These statistics make it easy to determine the parts of code that need optimization.
In particular, cProfile provides the following data for a function or script:
tottime
divided by ncallscumtime
divided by tottime
You can profile an individual function with the help of this:
import cProfile cProfile.run('spam()','spam.profile')
You can then view the results of profiling using another module called pstats
:
import pstats stats = pstats.Stats('spam.profile') stats.strip_dirs().sort_stats('time').print_stats()
More importantly, you can profile an entire script. Let's say you want to profile a script named myscript.py
. You simply navigate to the directory of the script using a command-line tool, and then type and run:
Python -m cProfilemyscript.py
This produces an output similar to the following:
1014 function calls in 0.093 CPU seconds Ordered by: standard name ncallstottimepercallcumtimepercallfilename:lineno(function) 1 0.000 0.000 0.000 0.000 Tkinter.py:3686(Studbutton) 1 0.000 0.000 0.000 0.000 Tkinter.py:3694(Tributton) 416 0.001 0.000 0.002 0.000 Tkinter.py:74(_cnfmerge) 1 0.011 0.011 0.028 0.028 myscript.py:19(<module>) 2 0.058 0.029 0.086 0.043 myscript.py:20(setAge) 7520.105 0.0000.257 0.129 myscript.py:23(findAudio) 10.001 0.001 0.013 0.013 myscript.py:25(createGUI) 1 40.004 0.000 0.005 0.005 myscript.py:4(saveAudio) 1 0.000 0.000 0.000 0.000 myscript.py:49(<module>)
After this, you can analyze the code to see the functions that take more time to execute. In our hypothetical example in the preceding output, we notice that the functions findAudio
and saveAudio
take the maximum time to execute. We can then analyze these two functions to see if they can be optimized.
In addition to the cProfile module, there are other modules, such as PyCallGraph and objgraph , and they provide visual graphs for profile data.
Optimization is a vast topic and there is a lot that you can do. If you are interested in knowing more about code optimization, you might start with the official Python optimization tips at the following link:
18.224.30.19