Some Not So Initial Python Impressions


Years ago I tried Python and instantly rejected it based on the imposed syntax rules of how whitespace was treated. To me this was a terrible idea and didn’t actually mesh at all with my sense of how my code should look. At the time I was doing a lot of Perl hacking and had a vested interest in what I had already invested in that platform.


Then I guess about a year ago I looked again at Python, this time with a new appreciation for the readability and perceived robustness of the language (not to mention a surging community). Having at this point spent time managing projects with multiple team members I had a new found respect for Python’s goal of having one obvious way to do something as opposed to the freeform nature of Perl or JavaScript (which I had a lot of experience with). I dabbled but still had no real work to do and so my foray didn’t go a lot further than to install PyDev for eclipse and create a few small test programs.


Third time’s the charm and this time around I’ve decided to make Python the back end for my new Silverlight application which I hope will assist in hosting it on Google’s app engine platform. [link to my own article]


I lost an hour or so dealing with Python terminology with “Module” vs “Package” vs “Class” so I thought I would write my thoughts. I was approaching my code thinking of classes as 1 per file where the filename and the class name match.


So I had the following structure for some initial classes:



Once I figured out how the __init__.py files worked and how to import properly then I had the following in my “__init__.py” of the GameEngine package:


__version__ = '0.0.1'

__all__ = ["Board","BoardPiece","BoardPosition","Player"]


Then in my test driver I had :


import os

import sys

from optparse import OptionParser


from SiliconTrader.GameEngine import *

#(OR)

#from SiliconTrader.GameEngine import Board



def main():

parser = OptionParser(usage="""

Testing program for the GameEngine classes, basically a throw away class for

learning some python....


Usage: %prog [options]

""")

board = Board()

board.helloBoard()


if __name__ == '__main__':

main()



And no matter what I tried in this case creating a new “Board” instance was always failing with the following error:


File "TestDriver.py", line 15, in main

board = Board()

TypeError: 'module' object is not callable


Being new to Python and without an internet connection (on holidays) I assumed my class was improperly defined, and then I assumed it was something to with reference paths. It was easy to prove the reference paths were fine as that will produce an entirely different error message. I played around with various incarnations of my class, including adding an __all__ = [‘Board’] to my Board.py file all to no effect.


Eventually I realized that I had created a module named Board and a class named Board and this is what was causing the error. Simply adding another “Board” to the reference in the above main statement fixes the problem (like so):


board = Board.Board()

board.helloBoard()


But that sucks for obvious reasons, so I re-ordered my packages and created modules that contained more than a single class so that I didn’t have to reference classes by a module name that matched the class.


So here’s an attempt to be more Python like:




Note that those green C icons are classes defined within the modules. This is a feature of the PyDev eclipse plugin and these the classes within “Model” above are all just in one text file. This isn’t terrible but it’s not ideal either, I can’t say I really like having all these classes defined in the same file, but the IDE makes things easy to navigate so until I see something easier this is how it will be. The import and creation code now looks like this by the way:


from SiliconTrader.Core import Model

from SiliconTrader.Core import Engine


#....

board = Model.Board()

board.helloBoard()

#....


I could have easily retained the * import but this is generally frowned upon and now that I am actually importing a set of classes with each line it’s much more inline with how I would want this to work.


Anyway, this is probably not something most people will get caught on, but coming from my daily C# existence I found this all a bit weird. Still easier than dealing with ruby classpaths though.