Python - Tips and Tricks


There's strictly no warranty for the correctness of this text. You use any of the information provided here at your own risk.


Contents:

  1. About Python
  2. How to execute a Python-script
  3. Programming in Python, getting help
  4. Using Python's interactive mode as a calculator
  5. File-operations and Filename globbing
  6. Generating random numbers
  7. Using Regular Expressions; Extracting HTML-Tags
  8. Date and Time
  9. Starting other processes from inside a Python-script
  10. Miscellaneous useful Python-methods and variables
  11. Conversions Between Decimal, Hexadecimal, Binary and Octal Numbers
  12. Installing modules
  13. Generating Bytecode of any script
  14. Encrypting and Decrypting Text Using a Password
  15. Scripting LibreOffice.org
  16. Plotting to the screen with Pygame
  17. Accessing MySQL-Databases
  18. Messageboxes with Tkinter
  19. Parse configuration-files using module "ConfigParser"
  20. PDF and Python
  21. Sending Emails
  22. Receiving Emails from a POP3-Server
  23. Setting up a small html-Server
  24. Writing Window-Applications using Tkinter
  25. Creating Windows ".exe"-Files From Python Scripts
  26. Encodings
  27. Writing Python-modules in C (Linux)
  28. Nice applications written in Python


1. About Python

Preface (2021): This is an old page about Python, I must have written in about 2008. Most information may still be valid though.

Today, there's a dispute about whether to use Python 3.x or Python 2.7. The most obvious change in Python 3 was, that "print" wasn't a command any more, but a function. So in Python 3 you always had to write brackets around things you wanted to print, like:

print("Hello")

As Python is a language that reduces the characters to write as much as possible (leaving out all the ";" and "{ ...} " found in other languages), many people found that change to "print" very annoying. They kept using Python 2.7. And so do I. So this page is about Python 2.7, and some code may need to be adapted, if it was to run on Python 3.x.
I hope, in Python 4 they make it possible again to write "print" without brackets. Or maybe allow the programmer to write it the way he or she wants (that is, with or without brackets).
Otherwise, Python 2.7 will still be the way to go.


Python is an interpreted programming language created by Guido van Rossum. It was first released in 1991.

The name "Python" referrs to the name of the comedy-group "Monty Python", not to the snake, but I use to ignore that, as I don't see such a big connection between the work of Monty Python and programming in general.

The Python-interpreter is freely available for Windows, Linux and Apple Mac OS-X.
If you run Linux or Mac OS-X, Python is probably already installed on your computer. Open a terminal, type "python" and you should be in its interactive mode (which you can leave with "CTRL+d" again).

With Python you can write small scripts doing just imperative programming as well as write large applications in a structured or in an object-orientated programming-style.

Python is designed to make things easy for the programmer. It provides flexible dynamic datatypes like lists and hashes (called "dictionaries") and takes care of memory management. It tries to come with

"Batteries included".

That means, a standard Python-distribution already has a lot of modules for many tasks, so there is a good chance, you can do what you want without searching and installing further modules and if you make your scripts available to other people, they can run them just like that.
But of course there are many very interesting modules that are not part of the Python-distribution too. A lot of those are listed here (a huge list, may take some time to load).

Python's syntax is as clear as possible, so its code is easy to read even years after writing.
This is achieved mainly by two unusual concepts:

1. In Python, everything is an object. Objects can have attributes and methods, so it is defined what can be done with them.
Therefore you don't have to declare variables, Python can read the variable-type from the context. For example if you do

a = 1

"a" becomes an object of type integer. You can verify this by doing:

print type(a)

So you don't have to write things like "int a = 1;" (like in C/C++) or even "my $a = 1;" (like in Perl) which makes code less readable.

2. In Python, code-indentation matters. Python reads the range of code blocks from the indentation-level:

for i in range(10):
    print i
    if i == 5:
        print "i is 5 now."

It's good coding style to use four space-characters for one indentation-level like in the example above.
Remember, readability matters!
So using Python, you don't need those ugly "{" and "}" like in C/C++, Java or Perl anymore.

While Perl's motto is "There's more than one way to do it." (TMTOWTDI), Python follows the concept of:

"There should be one -- and preferably only one -- obvious way to do it."

(Some of these concepts are shown as an easter-egg, if you do "import this" in Python's interactive mode.)

As the Python-interpreter is available for all three operating-systems mentioned above and most Python-functions can be called in a very general, high-level way, Python is very well suitable for writing platform-independent programs.

With Python you're not limited to writing text-only-console-programs. You can write GUI (= Window, point and click)-programs too. Bindings for many GUI-toolkits such as Tk, Gtk, wxWidgets, Qt, Windows-MFC and Apple-Cocoa are available. The Tk-module called "Tkinter" already comes with the Python-interpreter.

Besides the commonly used C-implementation of Python called CPython, which I mentioned above, there are also implementations in other languages. The Java-version is called Jython. With it (and the Java SDK), it is said to be possible to compile Python-code directly to Java-bytecode, that then can run on any Java Virtual Machine (but I haven't tested that yet.).

In general, Python is a high-level-programming-language (although you can accomplish surprisingly low-level-tasks with it too).
The code of a Python-program is 2-10 times shorter than the code of a comparable C/C++-program. It is much easier to understand too.
The price for that is, that C/C++ runs faster than Python.
Nevertheless, Python's speed is sufficient for a lot of tasks.
For example, Python-code may not be fast enough to render a 3D-shooter, but you can build a 3D-shooter with an engine written in C doing all the low-level-graphics-work and use Python to control that engine.


2. How to execute a Python-script

Executing a Python-script isn't difficult: Copy and paste its code into a text-editor.
On Windows, "Notepad.exe" will do, but you can also use an IDE ("Integrated Development Environment") like Pythonwin.
On Linux, I suggest learning how to use one of the editors "vim" or "emacs", but "kate", "gedit" or "kwrite" will do, too. There's also a nice IDE called Eric.
Make sure, that all characters are copied and pasted correctly and that all code-indentation is kept.
Then save the script as for example "script.py".
On Windows, you can then run the script by double-clicking it. If it's a GUI-application, you may want to get rid of the DOS-box that is usually opened. You can achieve this just by calling your script "script.pyw". In a DOS-box you can run your script by typing

python script.py

in its directory. On Linux, you have to make your script executable first. You can do that by executing

chmod +x script.py
After that you can run it by doing
./script.py

in its directory.


3. Programming in Python, getting help

I won't teach you here the basics of Python-programming; there already are enough ressources about that on the internet.

I recommend reading some of these free online-books (listed from easy to more difficult to understand) :

  • "A Byte of Python" (by Swaroop C H) (There's also a German version of this book)
  • The Python Tutorial (by Guido van Rossum) (on SuSE Linux, this comes in the python-doc...rpm-package)
  • "Think Python"
  • "Dive Into Python"
  • "Thinking in Python"

  • Interesting examples on how to do certain things can be found in the "Python-Cookbook".
    Answers to a lot of questions can be found in the "Python-FAQ". There's also a newsgroup "comp.lang.python".

    It's also a good idea to buy at least one printed book on Python-programming.

    Help on certain modules can be found using the "pydoc"-shell-command:

    pydoc time

    for example shows help about the "time"-module,

    pydoc time.sleep

    help about the "sleep"-method included in the "time"-module. There's also a "help()"-command in Python's interactive mode.

    Now I would like to show some things, you can do with Python.


    4. Using Python's interactive mode as a calculator

    Python has an interactive mode. It appears, if you just execute

    python

    Although it is not its main-purpose, you can use this interactive mode as a calculator. You can type there for example:

    print 42. * (87. - 32.4) / 3.4
    

    There's just one thing, you have to take care of:
    If you want to use integers like for example "42", you have to type them as float, that is with a point after them like "42.", which is short for "42.0". If you don't do that, you will probably get mathematically wrong results, because there are differences in the internal representations of the data-types "int" and "float" !

    After doing

    import math
    
    you can do even more advanced calculations there, for example:
    print math.sin(45.)
    

    or

    print math.pow(2., 3.)
    

    Please see "pydoc math" for details about the "math"-module.


    5. File-operations and Filename globbing

    This script demonstrates some often-used file-operations:

    #!/usr/bin/python
    # coding: utf-8
    
    import os
    import sys
    
    import glob
    
    # Get current working directory:
    PATH = os.getcwd()
    
    FILE = PATH + "/myfile.txt"
    
    # Test, if file exists:
    if os.access(FILE, os.F_OK):
        print "File already exists."
        sys.exit(1)
    
    fh = file(FILE, "w")
    
    fh.write("This is a line of text.\n")
    fh.write("This is another line.\n")
    
    fh.close()
    
    fh = file(FILE, "r")
    
    a = fh.readlines()
    
    fh.close()
    
    for i in a:
        print i.rstrip("\n")
    
    os.remove(FILE)
    
    print "The directory contains:"
    b = os.listdir(PATH)
    for i in b:
        print i
    
    # Filename globbing:
    print
    print "The directory contains the following html-files:"
    b = glob.glob("*html")
    if b:
        for i in b:
            print i
    else:
        print "None."
    

    For copying and moving files and directories and for deleting directories recursively, it is recommended to use the module "shutil".


    6. Generating random numbers

    Just like that:

    #!/usr/bin/python
    # coding: utf-8
    
    import random
    
    random.seed()
    
    for i in range(10):
        print random.randrange(10)
    


    7. Using Regular Expressions; Extracting HTML-Tags

    The Python-module "re" provides support for powerful regular expression (like in Perl).
    It seems, there are also the modules "re" and "pre".

    In fact, you don't need the regular-expression-modules very often: Many find- and replace-operations can already be done with Python's builtin string-functions like

    For simple find-operations, Python also offers an even more elegant and easy to use construction:

    #!/usr/bin/python
    # coding: utf-8
    
    mystring = "Hello World"
    
    if "World" in mystring:
        print '"World" found.'
    

    This also works with lists and tuples.

    Anyway, sometimes you can't avoid using regular expressions.
    For these cases, the following script shows, how it can be done with the "re"-module (although some people use the similar module "re" instead):

    #!/usr/bin/python
    # coding: utf-8
    
    import re
    
    # First, we define the text to be used:
    text = "Text to be searched."
    
    # Then, we compile a "pattern-object" from a regular expression:
    patobj = re.compile("s.*")
    
    # Now we can do a search-operation on the text:
    matchobj = patobj.search(text)
    
    if matchobj is not None:
        print "Regular expression found in the text."
    
    # We can also extract the substring found in the search-operation:
    
    if matchobj is not None:
        print text[matchobj.start() : matchobj.end()]
    
        # Alternatively, this may work:
        print matchobj.group()
    
    # Additionaly, we can do replace-operations on the text:
    print re.sub(patobj, "replaced.", text)
    
    # Instead of the search- and replace-operations operations above,
    # you could also do:
    
    if re.search("s.*", text):
        print "Found."
    
    print re.sub("s.*", "replaced.", text) 
    
    # But "re.compile()" is faster, if the regular expression is used
    # more than once.

    If you want to extract html-tags from a html-file, there's a problem with greed. You should then use a regular expressions with its last character as a negated character-class:

    #!/usr/bin/python
    # coding: utf-8
    
    import re
    
    html = """<html>
    <body>
    <h2>Caption 1</h2>
    <p>Some text.
    <h2>Caption 2</h2>
    <p>Some more text.
    <br>Going on.
    </body>
    </html>"""
    
    html = html.split("\n")
    
    patobj = re.compile("<h2>([^>]*)<\/h2>") # Notice the regexp here.
    for line in html:
        line = line.rstrip("\n")
        matchobj = patobj.search(line)
        if matchobj:
            print matchobj.groups()[0]

    The expression "<h2>([^>]*)<\/h2>" means:

    'Find "<h2>", then any amount of characters, that aren't ">" (and mark them for extraction), then "</h2>".

    The Tutorial says, you can also use "?" for marking an expression as being "not greedy" but the way above should be even more reliable.

    The best practice to extract text from a HTML-page in Python, would be using the module "Beautiful Soup".


    8. Date and Time

    This script demonstrates some often-used operations concerning date and time (using the a little low-level time-module):

    #!/usr/bin/python
    # coding: utf-8
    
    import time
    
    # Print current time in central European format including seconds:
    print time.strftime("%H:%M:%S")
    
    # On Linux, you can read more about format-strings like "%H:%M:%S"
    # by executing the shell-command "info date".
    
    # Print today's date in central European format; the numbers of days and months
    # below 10 are zero-padded (like in 09.08.2007):
    print time.strftime("%d.%m.%Y")
    
    # Print seconds since epoch (on Linux, epoch is 1.1.1970):
    print time.time()
    
    # Generate a time-tuple from seconds since epoch and print it:
    tmtp = time.localtime(time.time())
    print tmtp
    
    # Print today's date in central European format using the time-tuple generated above;
    # the numbers of days and months below 10 are blank-padded (like in 9.8.2007):
    print str(tmtp[2]) + "." + str(tmtp[1]) + "." + str(tmtp[0])
    
    # Convert the time-tuple back to seconds since epoch:
    print time.mktime(tmtp)
    

    If you want to calculate the time or the number of days between two or more dates, the datetime-module is even more useful:

    #!/usr/bin/python
    # coding: utf-8
    
    import datetime
    
    # Generate a datetime.date-object for today:
    d1 = datetime.date.today()
    print d1.strftime("%d.%m.%Y")
    
    # Generate a datetime.date-object for "30.01.2010":
    d2 = datetime.date(2010, 1, 30)
    
    # Now we can do some calculations with a datetime.timedelta-object:
    td = d1 - d2
    a = "Today is "
    if d1 > d2:
        a += str(td.days) + " days after "
    else:
        a += str(td.days * -1) + " days before "
    a += d2.isoformat() + "."
    print a
    
    try:
        feb29 = datetime.date(d1.year, 2, 29)
        print "This year is a leap year."
    except ValueError:
        print "This year is not a leap year."
    


    9. Starting other processes from inside a Python-script

    You can start other processes like that:

    #!/usr/bin/python
    # coding: utf-8
    
    import os
    
    os.system("ls")
    

    If you want to grab the process' output, you can do:

    #!/usr/bin/python
    # coding: utf-8
    
    import os
    
    ph = os.popen("ls")
    a = ph.readlines()
    ph.close()
    
    print a
    

    If you want to have more control over the started process, for example have it running for some time and pass commands to it while it's running, you should take a look at the Python-module

    subprocess

    On Microsoft Windows the command

    os.startfile("somefile.html")

    is very useful: It starts a file with its connected application (like clicking on its icon in "Explorer").
    So in the example above, the system's default-browser is started showing "somefile.html".
    That way, you don't have to worry about the application's correct start-command. Very nice.


    10. Miscellaneous useful Python-methods and variables

    "234".isdigit()	   Returns "True", if the string contains just numbers.
                       More info: "pydoc __builtin__".
    chr(65), ord("A")  These two functions convert an integer to an ASCII-code-string and back.
                       The results here are "A" and 65.
    dir(object)        Gives useful information about an object, especially about the names
                       of its methods.
    list.remove("a")   Removes the first element containing "a" from the list. Warning:
                       If "remove()" is used while iterating over the list,
                       the list and the loop get corrupted. In these cases always
                       remove from a copy of the list instead.
    sys.argv           A list, that holds the name of the Python-script and the
                       arguments passed to it from the command line.
    time.sleep(0.5)    Lets your Python sleep for half a second.
                       This may not be useful in GUI-applications. For Tkinter
                       please read "pydoc Tkinter.Tk" about "after" and "after_idle".
    type(object)       Returns the type of an object; check with the special
                       construction "if type(a) == str:", for example.
    


    11. Conversions Between Decimal, Hexadecimal, Binary and Octal Numbers

    The following script shows, how these number-conversions can be done:

    #!/usr/bin/python
    # coding: utf-8
    
    hexnum = "FF";
    decnum = 255;
    binnum = "11111111";
    octnum = "377";
    
    # Hexadecimal to decimal:
    print int(hexnum, 16)
    
    # Hexadecimal numbers start with "0x":
    print 0xFF
    
    # Decimal to hexadecimal:
    print hex(decnum)
    print "%X" % decnum
    
    # Binary to decimal:
    print int(binnum, 2)
    
    # Decimal to binary:
    print "{0:08b}".format(decnum)
    
    # Octal to decimal:
    print int(octnum, 8)
    
    # Octal numbers start with "0".
    # They are used for example in functions like os.chmod().
    print 0377
    
    # Decimal to octal:
    print oct(decnum)
    print "%o" % decnum

    Notice, that the functions hex() and oct() return a string.

    It seems, in earlier Python version (Python 2.4 and such) there wasn't built-in support for decimal-to-binary-conversion. A function "posdec2bin()" could have been used instead:

    def posdec2bin(decnum):
    
        hexbin = {"0":"0000", "1":"0001", "2":"0010", "3":"0011",
                  "4":"0100", "5":"0101", "6":"0110", "7":"0111",
                  "8":"1000", "9":"1001", "A":"1010", "B":"1011",
                  "C":"1100", "D":"1101", "E":"1110", "F":"1111"}
    
        hexnum = hex(decnum)[2:]
        hexnum = hexnum.upper()
    
        binlist = []
    
        for i in hexnum:
            binlist.append(hexbin[i])
    
        binstring = "".join(binlist)
        binstring = binstring.lstrip("0")
        return binstring


    12. Installing modules

    Modules often come with a "setup.py"-file. Usually, it should be run as root with

    python setup.py install

    Help on more commands "setup.py" knows, can be found doing

    python setup.py --help-commands


    13. Generating Bytecode of any script

    When you execute a Python-script, bytecode is generated. Sometimes it is saved as a .pyc-files. These files can be executed by Python just like .py-files. They start a little faster too, but don't run faster. They don't contain plain-text, so they can't be viewed in an editor directly, but they can be retransformed to .py-files by using something like this.
    However, if you want to generate a .pyc-file for a certain .py-file, you can use the script "compileall.py", that comes with your Python-distribution.


    14. Encrypting and Decrypting Text Using a Password

    First, download these two modules and install them:

    pycrypto
    yawpycrypto and also its "Flatten"-module.

    Then you should be able to run the following example-script:

    #!/usr/bin/python
    # coding: utf-8
    
    import os
    import sys
    import base64
    
    from yawPyCrypto.Cipher import DecryptCipher, EncryptCipher
    from yawPyCrypto.Cipher import ZipDecryptCipher, ZipEncryptCipher
    from yawPyCrypto.Constants import CIPHER_BLOWFISH, MODE_CBC
    
    
    def doEncrypt(text, passw = None):
    
        e = EncryptCipher(passw, CIPHER_BLOWFISH, MODE_CBC)
        e.feed(text)
        e.finish()
        encryptedtext = e.data
    
        if passw != None:
            passwr = passw
        else:
            passwr = e.password
    
        a = (encryptedtext, passwr)
        return a
    
    
    def doDecrypt(encryptedtext, passw):
        d = DecryptCipher(passw)
        d.feed(encryptedtext)
        d.finish()
        decoded = (d.data)
        return decoded
    
    
    # Calling the encryption routine.
    # If you just pass the text to encrypt, a password is generated:
    
    a = doEncrypt("For your eyes only !", "Melina")
    
    
    # Just trying to clean the screen:
    
    if sys.platform == "win32":
        os.system("cls")
    else:
        os.system("clear")
    
    print
    print "Hello !"
    print
    print "I just encrypted some text. It looks like this now:"
    print
    
    print base64.b64encode(a[0])
    
    print
    print 'Please notice, that I just encoded the text once more using "base64.b64encode()" to make it printable.'
    print
    print "The password for decryption is: "
    print
    print base64.b64encode(a[1])
    print
    print "Let's decrypt again (the original password must be passed without b64encoding):"
    print
    print doDecrypt(a[0], a[1])
    print
    

    Sometimes, it's not necessary to use Python for such tasks. You can do encryption and decryption with programs like "gpg" too:

    #!/bin/bash
    
    # Cleanup, if the script has been run before:
    
    a="unencrypted.txt encrypted.txt decrypted.txt"
    
    for i in $a
    do
        if test -f "$i"
        then
            rm "$i"
        fi
    done
    
    echo 'For your eyes only !' > unencrypted.txt
    
    # Encrypting to file 'encrypted.txt' using password "Melina":
    echo 'Melina' | gpg --batch --textmode --passphrase-fd 0 -o encrypted.txt -c unencrypted.txt
    
    # Decrypting to file 'decrypted.txt' using password "Melina":
    echo 'Melina' | gpg --batch --textmode --passphrase-fd 0 -d encrypted.txt > decrypted.txt
    


    15. Scripting LibreOffice.org

    You can use Python as a scripting language for LibreOffice. To be able to do that, you have to do two things first:

    1. There's a Python-module called "uno.py" that needs to be imported in the Python-script. "uno.py" comes with LibreOffice. It should be in its "program"-directory. You have to make sure, that it can be found by Python. This can be done by putting a file "uno.pth" into the python-path, for example to "/usr/lib/python/site-packages". The file "uno.pth" needs to contain just the path to the LibreOffice-"program"-directory, for example

    /usr/lib/libreoffice/program

    2. To accept python-scripting, LibreOffice needs to be activated in a special server-mode. This is done by starting it with

    oowriter -accept="socket,host=localhost,port=2002;urp;"

    If it's started this way, it accepts scripting from a script like this:

    #!/usr/bin/python
    
    import uno
    from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
    
    # Initializing:
    local = uno.getComponentContext()
    resolver = local.ServiceManager.createInstanceWithContext ("com.sun.star.bridge.UnoUrlResolver", local)
    context = resolver.resolve ("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
    desktop = context.ServiceManager.createInstanceWithContext ("com.sun.star.frame.Desktop", context)
    
    # Creating a new document:
    document = desktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, () )
    
    # This would write into the current document instead, if one was already loaded:
    # document = desktop.getCurrentComponent()
    
    cursor = document.Text.createTextCursor()
    
    document.Text.insertString(cursor, "Hellow", 0)
    
    # Doing a "Backspace" deleting the "w" from "Hellow":
    cursor.goLeft(1,1)
    cursor.setString("")
    
    # Insert a "Return":
    document.Text.insertControlCharacter(cursor, PARAGRAPH_BREAK,0)
    
    document.Text.insertString(cursor, "Hello from Python.", 0)
    
    """
    Other things (this part is currently not executed):
    
    Loading a new document would be:
    document = desktop.loadComponentFromURL("file:///home/user/letter.odt", "_blank", 0, () )
    cursor = document.Text.createTextCursor()
    
    Going to an already existing Bookmark named "bmark" would be:
    Bookmark = document.Bookmarks.getByName(bmark)
    cursor = document.Text.createTextCursorByRange(Bookmark.Anchor)
    
    Inserting into an already existing TextFrame called "name" would be:
    frames=document.getTextFrames()
    frame=frames.getByName(name)
    cursor = frame.Text.createTextCursor()
    frame.Text.insertString(cursor, "Hello.", 0)
    """
    


    16. Plotting to the screen with Pygame

    The Pygame-modules provide Python-access to SDL, a multimedia-library comparable to MS DirectX.
    Pygame gives you a window in which you can draw graphical objects, move them around and remove them again. It also provides modules for processing keyboard- and mouse-events and for playing several sounds and additionally music at the same time.
    So, within certain speed-limits, you can use Pygame to program 2D-games. The games "SolarWolf" and "Barbie Seahorse Adventures" give an example of what is possible with Pygame.
    To get sound working correctly with my soundcard, I have to do

    export SDL_AUDIODRIVER=alsa

    before starting a Pygame-application.

    From time to time there are Pygame-programming-competitions at PyWeek. You can download a lot of interesting Pygame-games there.

    Pygame's capabilities can also be used for other purposes than game-programming. Here is a script, that calculates some mathematical object and plots it to the screen. The picture is calculated and even plotted point by point, but the screen is only updated once, after calculation has been finished. Otherwise the script would run much slower. Press "q" to quit it:

    #!/usr/bin/python
    # coding: utf-8
    
    import pygame, sys,os
    import math
    from pygame.locals import *
     
    # Screen resolution:
    
    RESX = 800
    RESY = 600
    
    pygame.display.init()
    
    window = pygame.display.set_mode((RESX, RESY))
    
    pygame.display.set_caption('Gauss') 
    screen = pygame.display.get_surface() 
    
    b = 0.3
    ULIM = 100.
    UDIV = 1.8
    
    for u in range(0, int(ULIM), 1):
        # Some mathematical, Gaussian calculations:
        a = float(u) / (ULIM / UDIV)
        if u > ULIM / 2:
            a = UDIV - (float(u) / (ULIM / UDIV))
        m = u / 16.
    
        for x in range(50, RESX - 50):
            c = x / (RESX / 16.) - 5.
            y = a * math.exp(-b * (c - m) * (c - m))
    
            # down:
            y = RESY / 10 + (y * RESY / 1.5 + u * 3)
    
            # up:
            # y = RESY * 9 / 10 - (y * RESY / 1.5 + u * 3)
    
            pygame.draw.line(screen, (200,200,200), (x, y), (x, y), 1)
    
    pygame.display.update() 
     
    def input(events): 
       for event in events:
            if event.type == QUIT:
                sys.exit(0) 
            if event.dict.has_key('key') and event.dict['key'] == K_q:
                sys.exit(0) 
     
    while True: 
       input(pygame.event.get())
    


    17. Accessing MySQL-Databases

    MySQL is a free database-system written in C/C++. It is included in most modern Linux-distributions. With it you can setup a powerful database-server, make it start at system-startup, create databases with lots of tables, populate those tables with data, search for that data and so on. The MySQL-server is fast, and you can store millions of records in its databases.
    You talk to it using the database-language SQL ("Structured Query Language"). Please notice, that MySQL uses its own user "root", who is different from the "root" of the Linux-system.

    With the module mysql-python you can access MySQL-databases from Python. Probably you don't have to download the module. On SuSE-Linux 10 for example it can be found in the package "python-mysql....rpm". A small tutorial how to use the module can be found here.

    The following example requires, that a MySQL-server has been set up and started. It also requires, that a MySQL-database "lang" with password "MyPassword" for user "root" and inside the database a table "languages" has been created and filled with some data. If the server is running and "root"'s password is "MyPassword", you can create and populate the database and its table automatically by saving the following SQL-code as "langs.mysql":

    # langs.mysql: Just some example data.
    
    DROP DATABASE IF EXISTS `lang`;
    CREATE DATABASE `lang`;
    USE `lang`;
    
    DROP TABLE IF EXISTS `languages`;
    
    CREATE TABLE `languages` (
      `Nr` int(11) NOT NULL default '0',
      `Name` varchar(30) NOT NULL default '',
      `LearnDate` date NOT NULL default '0000-00-00',
      `Impression` varchar(50) NOT NULL default '',
      `Score` decimal(9,2) NOT NULL default '0.00',
      PRIMARY KEY  (`Nr`)
    ) TYPE=MyISAM;
    
    INSERT INTO `languages` (`Nr`,  `Name`, `LearnDate`, `Impression`, `Score`) VALUES (1, 'C', '2001-01-01', 'Fast, but difficult.', '2.00');
    INSERT INTO `languages` (`Nr`,  `Name`, `LearnDate`, `Impression`, `Score`) VALUES (2, 'Perl', '2002-03-25', 'Nice, but terse syntax.', '2.50');
    INSERT INTO `languages` (`Nr`,  `Name`, `LearnDate`, `Impression`, `Score`) VALUES (3, 'Python', '2004-05-01', 'Clean syntax, flexible.', '3.00');

    Then run this command on it (Warning: If a database "lang" already exists on the MySQL-server, it is deleted without warning):

    mysql -u root -pMyPassword < langs.mysql

    With the module mentioned above, this Python-script accesses the table "languages" in the database "lang" and prints each of its records as a tuple:

    #!/usr/bin/python
    # coding: utf-8
    
    import MySQLdb
    
    conn = MySQLdb.connect(host = "localhost",
                          user = "root",
                          passwd = "MyPassword",
                          db = "lang")
    
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM languages")
    
    while 1:
        row = cursor.fetchone()
        if row == None:
             break
        print row
    
    cursor.close()
    conn.close()


    18. Messageboxes with Tkinter

    Tkinter is one of the GUI-toolkits available for Python. With it, you can create window-applications.
    Actually Tkinter is an interface to Tk, the GUI-toolkit of the language "Tcl", but usually you won't notice that.
    Tkinter is quite small in relation to other GUI-toolkits. That's why it comes with the Python-interpreter, although its windows don't look too beautiful.

    The following script "msgbox.py" provides a simple messagebox in Tkinter. You can use it on Linux for example if you have difficulties with the font-size of Xdialog:

    #!/usr/bin/python
    # coding: utf-8
    
    # msgbox.py
    
    import os
    import Tkinter as tk
    
    class MyMsgBox:
    
        def __init__(self, title = "My Title", msg = "Some text"): 
            if os.name == "nt":
                self.appfont = "{Arial} 10 {normal}"
            elif os.name == "posix":
                self.appfont = "{suse sans} 15 {normal}"
            else:
                self.appfont = "{suse sans} 15 {normal}"
            self.mw = tk.Tk()
            self.mw.title(title)
            # self.mw.iconname(iconname)
            self.mw.geometry("+350+300")
            self.mw.option_add("*font", self.appfont)
            self.label = tk.Label(self.mw, text = msg)
            self.label.pack(side = tk.TOP, anchor = tk.W, padx = 50, pady = 10)
    
            self.btn_exit = tk.Button(self.mw, text = "Ok", command = self.mw.destroy)
            self.btn_exit.focus()
            self.btn_exit.bind('<Return>', self.mwDestroy)
            self.btn_exit.pack(side = tk.RIGHT, anchor = tk.E, padx = 20, pady = 15)
            self.mw.mainloop()
    
        def mwDestroy(self, a):
            self.mw.destroy()
    
    if __name__ == "__main__":
       app = MyMsgBox("Hello", "Some text.")
    

    You can run "msgbox.py" directly, but in general it is meant to be used as a module that is called from another script:

    #!/usr/bin/python
    # coding: utf-8
    
    from msgbox import MyMsgBox
    
    msgb = MyMsgBox("Window", "Hello from the controlling script.")

    If you have already an opened Toplevel-tkinter-window, you can even do this instead:

    #!/usr/bin/python
    # coding: utf-8
    
    import tkMessageBox
    
    tkMessageBox.showinfo(title = "Hello",
                          message = "Some text")
    


    19. Parse configuration-files using module "ConfigParser"

    With Python you can parse configuration-files using the module "ConfigParser", which is part of the Python-distribution.
    The configuration-files have to be in a standard-format: They must have sections, followed by options and values in a format like this:

    [section]
    option=value
    option=value
    
    Take for example the configuration-file for the KDE-editor "kate" called "katerc". If "kate" is installed, it can be found here:
    /home/user/.kde/share/config/katerc

    If your "katerc" looks like this:

    [$Version]
    update_info=kate-2.4.upd:kate2.4
    
    [Filelist]
    Edit Shade=255,102,153
    Shading Enabled=true
    Sort Type=0
    View Shade=51,204,255
    
    [General]
    Days Meta Infos=30
    Modified Notification=false
    

    you can use the following Python-script in its directory to parse it:

    #!/usr/bin/python
    # coding: utf-8
    
    import ConfigParser
    
    c = ConfigParser.ConfigParser()
    
    # Read in the configuration in file "katerc":
    c.read("katerc")
    
    secs = c.sections()
    
    print
    print "These are all sections, options and values:"
    print
    
    for i in secs:
        print i
        opts = c.options(i)
        for u in opts:
            value = c.get(i, u)
            print "\t" + u + "\t\t\t" + value
    print
    
    # Setting all values to "MyValue":
    for i in secs:
        opts = c.options(i)
        for u in opts:
            c.set(i, u, "MyValue")
    
    # Uncommenting the following lines would write the configuration
    # stored in object "c" to a file "out.conf":
    #
    # FH = file("out.conf", "w")
    # c.write(FH)
    # FH.close()
    # print "New configuration written to file 'out.conf'." 
    

    Please see "pydoc ConfigParser" for further information.


    20. PDF and Python

    For creating new PDFs using Python, I suggest the open-source-version of the "ReportLab" module-library.
    With it, you can for example create a simple "Hello World"-pdf named "hello.pdf" like that:

    #!/usr/bin/python
    # coding: utf-8
    
    from reportlab.pdfgen import canvas
    
    c = canvas.Canvas("hello.pdf")
    c.drawString(100, 100, "Hello World")
    c.showPage()
    c.save()
    

    For postprocessing already existing PDFs, I suggest using the "pyPDF"-module. It can

    There's also ReportLab's "Pagecatcher" to do such things even more professionally, but it's not free.


    21. Sending Emails

    Python comes with everything that is needed to establish an email-client without the help of other programs.
    Modules included are "smtplib" and "email".

    Sending emails is very easy with the script "simplemail.py", which is a wrapper around the modules mentioned above. With it you can send email just like that:

    #!/usr/bin/python
    # coding: utf-8
    
    from simplemail import Email
    
    Email(from_address = "sender@someadress.com",
          to_address = "receiver@someotheradress.com",
          subject = "Some subject.",
          message = "This is the message's text."
        ).send()
    


    22. Receiving Emails from a POP3-Server

    Email's data-format was originally meant for transmitting just plain text. So all data, even of attachments like .jpg- or .mp3-files, is encoded and put together into a single text-message. Such a message has headers beginning with "To:" or "Date:", followed by the email's text and so on.
    So after receiving an email-message from a server, you have to parse it into the parts you're interested in. You can do this with the module "email.Message".

    The following script accesses a POP3-email-server "pop3.exampleserver.com", fetches all emails for user "user@exampleserver.com" there using password "examplepassword" and stores all email-parts including attachments in a handy Python-list. The script just prints this list, but of course you can do much more interesting things with it like for example extract only the messages' texts or save the attachments.
    As you can see, element four of the list is the attachment stored as another list with just two elements, the attachment-filename and the attachment-data. The later can be saved using "fp = file(filename, "wb")" and proceeding as described above in "File-operations":

    #!/usr/bin/python
    # coding: utf-8
    
    import sys
    import poplib
    import email
    from email.Message import Message 
    
    HOST = "pop3.exampleserver.com"
    USER = "user@exampleserver.com"
    PASSWORD = "examplepassword"
    
    def getAllEmails(host, user, passw): 
    
        try:
            M = poplib.POP3(host)
        except:
            print "Error: Email-server not found."
            sys.exit(1)
    
        try:
            M.user(user) 
            M.pass_(passw)
        except:
            print "Error loging in: Maybe invalid username or password."
            sys.exit(2)
        
        emails = [] 
             
        maillist = M.list()[1]
    
        if len(maillist) > 0: 
    
            for mailnr in range(len(maillist)):
    
                adress = "" 
                subject = "" 
                content = "" 
                attachment = [] 
    
                m = email.message_from_string("\n".join(M.retr(mailnr + 1)[1]))
    
                types = m.items() 
                     
                for a in types:
    
                    if a[0] == "From": 
                        adress = a[1] 
    
                    if a[0] == "Subject":
                        subject = a[1]
                                     
                for part in m.walk(): 
    
                    if part.get_content_maintype() == 'multipart': 
                        continue 
     
                    if part.get_content_maintype() == "text":
                        content = part.get_payload(decode = True)
                             
                    if  part.get_filename() is not None: 
                        attachment.append([part.get_filename(), part.get_payload(decode = True)]) 
                     
                emails.append([mailnr + 1, adress, subject, content, attachment]) 
    
        M.quit() 
    
        return emails
    
    a = getAllEmails(HOST, USER, PASSWORD)
    print a
    

    It is also possible to delete emails directly on the distant server using "poplib.dele()".


    23. Setting up a small html-Server

    It's amazing, that it's possible to set up a small html-server with just a few lines of Python-code:

    #!/usr/bin/python
    # coding: utf-8
    
    # httpd.py
    
    import sys
    
    from BaseHTTPServer import HTTPServer
    from CGIHTTPServer import CGIHTTPRequestHandler
    
    serveradresse = ("", 8080)
    server = HTTPServer(serveradresse, CGIHTTPRequestHandler)
    
    try:
        print
        print "Serving:"
        print "Please open a browser and point it to \"http://localhost:8080/test.html\""
        print "Press \"CTRL+c\" to exit."
        server.serve_forever()
    
    except KeyboardInterrupt:
        print "Bye."
        sys.exit
    

    It can manage .html-files found in and below its directory.
    For example, you can put a file "test.html" there and access it with an internet-browser pointing to "http://localhost:8080/test.html".
    If you just go to "http://localhost:8080/", the server tries to show you a page "index.html" in its directory.
    You can also use the server to test your CGI-scripts.

    Right now, I don't know how to make this small server part of the internet.
    I doubt that it can handle too many accesses at once. For larger tasks I suggest using something like "Apache".


    24. Writing Window-Applications using Tkinter

    Writing Python-window (GUI)-applications using Tkinter is an interesting, but more complex subject.

    Therefore, I've written another page about that, that can be found here.


    25. Creating Windows ".exe"-Files From Python Scripts

    Especially on Windows, many users seem to be reluctant to install the Python interpreter. They are used to computer programs coming as Windows executables, that is as ".exe"-files. Not as scripts with the file extensions ".py" or ".pyw", that look unfamiliar to them.
    However, it is possible, to pack the parts of the Python interpreter and all the modules needed by a script to run, into a single ".exe"-file. That way, the script can also be handed out to users, that couldn't cope with installing the Python interpreter or even additional modules.

    A program to create such a Windows executable is PyInstaller. To turn a GUI-script into a single ".exe"-file, it would be run like this:

    pyinstaller --onefile --windowed yourscript.pyw

    More options of PyInstaller can be found here.

    Another way to create such an ".exe"-file would be py2exe. As it's an extension to the "distutils"-package, it has to be used a bit differently.
    First, a file called "setup.py" has to be created, which holds all the options and points to your Python script. "setup.py" may look like this:

    # setup.py
    from distutils.core import setup
    import py2exe, sys, os
    
    sys.argv.append('py2exe')
    
    setup(
        options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
        windows = [{'script': "yourscript.pyw"}],
        zipfile = None,
    )

    Then, this command is run to create the ".exe"-file:

    python setup.py py2exe

    By default (with a simpler "setup.py"-file) py2exe creates a large directory with a much smaller ".exe"-file and all the library-files needed to run it.

    More options of py2exe's "setup.py"-file can be found here.


    26. Encodings

    The encoding-line at the beginning of a script tells the script, which encoding the script uses:

    # coding: utf-8

    for UTF-8 or

    # coding: iso-8859-1

    for ISO-8859-1 (= Latin 1).

    Sometimes, there can be problems with encodings, when you try to ouput text, either to the console or to GUIs (like Tkinter). I suggest, experimenting with "str.decode()" or "str.encode()" then. Often, 'str.decode("iso-8859-1")' helps:

    #!/usr/bin/python
    # coding: iso-8859-1
    
    a = "Zwölf Boxkämpfer jagen Eva quer über den großen Sylter Deich."
    print a.decode("iso-8859-1")

    On Linux, the result depends on the system locales, printed by the "locale"-command, like for example "$LANG". "$XTERM_LOCALE" may be another variable to look for.


    27. Writing Python-modules in C (Linux)

    Usually you don't have to write Python-modules in C, because you can just "import" every Python-script as a module into another script.

    But it's interesting to see, that it is possible to mix Python and fast C-code. So here's an example (according to an article in "Linux-Magazin" from 2002):

    There will be three small files: "gcd.c", "mymod.c" and "setup.py".
    "gcd.c" contains a C-function we want to call from Python. "mymod.c" and "setup.py" are needed to build the module. "mymod.c" describes the contents of "gcd.c" to the build-routine. It's a problem to make the datatypes of Python and C accessible from the other language.

    This is "gcd.c":

    /* gcd.c */
    
    int gcd(int x, int y)
    {
        int g = y;
    
        while (x > 0)
        {
            g = x;
            x = y % x;
            y = g;
        }
    
        return g;
    }
    

    Here comes "mymod.c":

    #include <Python.h>
    extern int gcd(int, int);
    
    /* mymod.c */
    
    /* Wrapper-functions for gcd() */
    static PyObject* wrap_gcd(PyObject* self, PyObject* args)
    {
        int a, b, res;
    
        if (!PyArg_ParseTuple(args, "ii", &a, &b))
        {
            return 0;
        }
    
        res = gcd(a, b);
        return Py_BuildValue("i", res);
    }
    
    /* Listing of all module-functions */
    static PyMethodDef mymodMethods[] =
    {
        {
            "gcd", wrap_gcd, METH_VARARGS
        },
        {
            0
        }
    };
    
    /* Function is called when doing "import mymod". */
    void initmymod()
    {
        Py_InitModule("mymod", mymodMethods);
    }
    

    This is "setup.py":

    #!/usr/bin/python
    # coding: utf-8
    
    # setup.py
    
    from distutils.core import setup, Extension
    
    setup(name = "mymod",
          version = "0.01",
          maintainer = "whoever",
          ext_modules = [Extension('mymod', sources=['mymod.c', 'gcd.c'])]
          )
    

    Now put these three files into a directory, then do

    chmod +x setup.py
    and after that
    ./setup.py build

    A subdirectory "build" should have been created (the C-compiler "gcc" needs to be installed for this). Somewhere in the subdirectory a file "mymod.so" should be found. That's your new Python-module. Now you can do in its directory:

    #!/usr/bin/python
    # coding: utf-8
    import mymod
    print mymod.gcd(40, 8)
    

    and should get a result of "8".

    More on this topic here.


    28. Nice applications written in Python

    1. PyMP3Cut: Splits an mp3-file into smaller mp3-files. Doesn't convert anything to "wav" in between, runs fast. Can extract sound-segments from the middle of an mp3-file, too.
    2. Barbie Seahorse Adventures: A 2D-plattform-game (uses Pygame).
    3. PySol: A collection of Solitaire card games like, for example, "Klondike".


    Back

    Author: hlubenow2 {at-symbol} gmx.net