RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


A Developer's Guide to Python 3.0: Standard Library : Page 5

The changes to the standard library in Python 3.0 truly "clean house." The results are both more usable and less cluttered.


Modified Modules

Many of the already-existing modules have been modified in Python 3.0. I've picked the ones that I think are the most important and interesting, but you should be aware that there are others, some of which might be the most important and interesting to you.

The os Module

The os module gained some new functionality. It now handles open files and symlinks much better on *NIX systems. The fchmod() and fchown() functions can change the mode and owner of an open file; they work just like chmod() and chown() but accept the file object itself rather than its path. The lchmod() function changes the mode of a symlink. In addition the os.walk() function can now follow symlinks if the new followlinks argument is True (it's False by default for backward compatibility).

The os.path module has a few useful modifications. The splitext() function used to split a string on the last dot, which resulted in a strange splitting for *NIX-formatted dot files such as .bashrc:

   >>> os.path.splitext('.bashrc')
   ('', '.bashrc')
In Python 3.0, leading dots are ignored, which results in a more natural splitting:

   >>> os.path.splitext('.bashrc')
   ('.bashrc', '')
A new function, os.path.relpath returns the relative path from a given start path. This is very useful when dealing with lots of nested files and directories (which happens often):

   >>> os.path.relpath('/a/b/c/d.txt', '/a/b')
os.path.expandvars() used to be a *NIX function that expanded shell variables of the form $VAR and ${VAR}. Now, it works on Windows too, and can expand environment variables of the form %VAR% (the Windows shell naming convention):

   >>> os.environ['PROJECTS'] = 'c:/projects'
   >>> os.path.expandvars('%PROJECTS%/cool_project')
The os.path.expanduser function also works on Windows now. It uses the *NIX convention of converting the tilde (~) symbol into the user's home directory:

   >>> os.path.expanduser('~')
   'C:\\Documents and Settings\\gigi' 

The turtle Module

Python 3.0 supplies an extensive reimplementation of the turtle module. I had never even heard of the turtle module before, and I was pretty surprised to find out it's a Tkinter-based turtle graphics module similar to Logo. Logo is an educational programming language intended to simplify teaching programming to kids. The idea is that you have a "turtle" on-screen that you control with simple commands.

You can work with the turtle interactively from the command line. First, you need to create a turtle object, which automatically pops up a graphics window, and places the turtle in the center pointing to the right:

   from turtle import Turtle
   t = Turtle()
Subsequently, you can interact with the turtle and tell it what to do. The following commands draw a triangle on the screen by telling the turtle to move forward (fd) 100 pixels, and then turn 120 degrees to the right (rt), repeated three times:

   >>> for i in range(3):
   ...   t.fd(100)
   ...   t.rt(120)
Here's a short turtle script that draws a yellow and purple checkered board. It uses several new commands and capabilities. The pu (pen up) command tells the turtle to lift the pen (not draw). The pd (pen down) command tells it to start drawing again. The goto command causes the turtle to move to an absolute position (the center of the screen is 0,0). The color command sets pen and fill colors. The begin_fill and end_fill wrap turtle commands and serve to fill a drawn shape. This time, the code turns the turtle to the left with the lt command:

   from turtle import Turtle
   t = Turtle()
   def draw_square(t, x, y, d, c):
     print (x, y)
     t.goto(x, y)
     t.color('black', c)
     for i in range(4):
   d = 100  # size of each square will be d x d pixels
   n = 4   # will draw a checkered board of size n x n
   # Make sure the whole thing is centered
   offset = -(d * n / 2)
   for x in range(n):
     for y in range(n):
       c = 'purple' if (x + y) % 2 == 0 else 'yellow'
       draw_square(t, offset + x * d, offset + y * d, d, c)
Figure 1. Fancy Turtle Graphics: This complex looping shape was generated by a short Logo program translated to Python and uses the turtle module.
Here's another program translated from Logo that draws a fancy loopy shape (see Figure 1):

   from turtle import Turtle
   t = Turtle()
   for i in range(36):
     for j in range(36):
Finally, the reset command simply erases everything already drawn and moves the turtle to the center of the screen, pointing to the right.

The turtle module is a lot of fun, but you can also use it for more serious purposes such as drawing charts and graphs, circles, and even text.

The ctypes Module

The ctypes module is a very slick foreign function interface. It became part of the standard library in Python 2.5 and continues to improve. It allows you to access C DLLs and shared libraries. For example, here's how you can display a standard Windows message box:

   >>> import ctypes
   >>> ctypes.windll.user32.MessageBoxW(0, 'ctypes rocks!', 'Title', 0) 
This goes almost directly to the Win32 C API. On Unix/Linux/Mac OSX you access libraries with the cdll object. The following code snippet calls the rand() function in the C runtime library (libc). The code first finds the libc in a cross-platform way (works on Linux and on OSX) using the find_library() function. It then loads the library using the CDLL call and finally calls libc.rand() in a loop.

   import ctypes
   from ctypes.util import find_library
   libc_path = find_library('c')
   libc = ctypes.CDLL(libc_path)
   for i in range(4):
     print(libc.rand() % 10)
The ctypes module now has a C99 Bool type. I'm not sure how useful it is. Perhaps you might need it if you have a C dynamic library that uses the C99 Bool type in its API as an input or output argument, or as a member in a struct/union. Here is how you create a c_bool value from a Python int:

   >>> from ctypes import c_bool
   >>> c_bool(7)
You can pass virtually any Python value to construct a c_bool. The rules are simple: Python's False is False (duh!), every zero numeric value (int, float, complex, fractions.Fraction, decimal.Decimal) is False, None is False, an empty string is False. Everything else (including functions, objects and classes) is True:

The following code lists all the False values:

   >>> import decimal
   >>> import fractions
   >>> from ctypes import c_bool
   >>> c_bool(False)
   >>> c_bool(None)
   >>> c_bool('')
   >>> c_bool(0)
   >>> c_bool(0.0)
   >>> c_bool(decimal.Decimal('0.0'))
   >>> c_bool(fractions.Fraction(0, 5)
   >>> c_bool(complex(0, 0))
And this code lists a representative sample of True values:

   >>> import decimal
   >>> import fractions
   >>> from ctypes import c_bool
   >>> c_bool(True)
   >>> c_bool('Something')
   >>> c_bool(-7)
   >>> c_bool(0.3)
   >>> c_bool(5.5)
   >>> c_bool(-4.4)
   >>> c_bool(decimal.Decimal('3.0'))
   >>> c_bool(decimal.Decimal('0.7'))
   >>> c_bool(decimal.Decimal('-2.2'))
   >>> c_bool(fractions.Fraction(0, 5)
   >>> c_bool(complex(3, 0))
   >>> c_bool(complex(0, 5))
   >>> c_bool(complex(-11.22, -11.22))
You can use the c_bool type just like a Python bool:

   >>> assert(ctypes.c_bool(True))
   >>> assert(not ctypes.c_bool(False))
The ctypes module always had arrays that you could slice using the array[start:end] syntax. Now, you use the full slice syntax array[start:end:step]. You can define a fixed-size array type by multiplying a ctypes data type by a fixed integer:

   int_6_array_type = c_int * 6
The preceding code just creates a type; you need to instantiate it to get a usable array object. You can initialize ctypes arrays with values in the constructor or fill them with a default value (0 for ints):

   a = int_6_array_type()
   for i in range(6):
     assert a[i] == 0
     a[i] = i
Slicing a ctypes array is just like Python's slicing. You can even use the [::-1] idiom to reverse them:

   >>> a[2:5]
   [2, 3, 4]
   >>> a[2:5:2]
   [2, 4]
   >>> a[::-1]
   [5, 4, 3, 2, 1, 0]
The result of slicing a ctypes array is a Python list and not another ctypes array:

   >>> type(a[1:4])
   <class 'list'>
Another improvement is better handling of errno (on *NIX systems) and GetLastError()/SetLastError() on Windows. In Python 2.5 you couldn't get to the actual value of errno or GetLastError(), because they were reset by other calls. Now, ctypes preserves a thread-local copy of this value if you load the library with the use_errno/use_last_error flag. After a call you may call ctypes.get_errno() or ctypes.get_last_error() to figure out what the error is.

To find out more about ctypes see my earlier DevX article on Python 2.5.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date