Interactive Python Scripting Example
For my first blog entry I wanted to write an article explaining what a dynamic language is. Since I prefer to think concretely about things, I'm going to start with an example of using a dynamic language (Python) to play with an interesting API. For now, my working definition of a dynamic language is any language which could be easily used for the following example.
I’m going to use Windows.Forms as a standard API for this demo. (Note: This probably won't work on Mono-1.0, but it shouldn't be hard to port this example to GTK#. Here's an example of using IronPython with GTK# for those who are interested.) If you want to follow along, you can download IronPython-0.6. Remember that IronPython is at a pre-alpha 0.6 release, so don’t be surprised if it has bugs.
Formatting note: I'm sorry if these examples are a little hard to read. I'm having trouble talking my blog editor into showing PRE blocks correctly. The extra lines are an artifact of the blog editor and are not intentional.
The first step is to bring up the interactive interpreter. This should be simple. See README.html in the IronPython zip file for a few more hints on different platforms.
C:\IronPython\bin> IronPythonConsole
>>>
Whenever I bring up a new interactive interpreter I feel compelled to get it to do some tricky math to let me know that it's really working.
>>> 2+2
4
Next we’ll create a new Form and show the window.
>>> from System.Windows.Forms import *
>>> from System.Drawing import *
>>> f = Form(Text="Experiment #1")
>>> f.ShowDialog()
You should see a nice little window popup now. However, there’s a big problem. f.ShowDialog has taken over the main thread and it’s impossible to type anything more at the interpreter prompt. Let’s fix that by first closing the window (click on the ‘X’). You should then see:
Cancel
>>>
Now let’s start the ShowDialog method in its own thread so that it doesn’t block the interpreter
>>> from System.Threading import *
>>> Thread(f.ShowDialog).Start()
>>>
Now we have our window showing and the interpreter is still “live” for us to keep typing at. We can change different properties of the form like this:
>>> f.MinimizeBox = False
>>> f.Size = Size(200,200)
>>> f.Text = "New Title"
It’s fun playing with the form, but we’d like to add a button to give it some more functionality.
>>> b = Button(Text="Push Me")
>>> f.Controls.Add(b)
System.ArgumentException: Controls created on one thread cannot be parented to a contro <snip>
Oops! That didn’t work as well as we might have liked. This is our second experience of the interactions between the threading model in Windows.Forms and the interactive interpreter. There are a number of creative solutions to this problem (see …) To keep things simple for this blog, we’re going to just close the window again, add the control, and then restart the main event thread. Don’t forget to close the window before proceeding with the next two lines.
>>> f.Controls.Add(b)
>>> Thread(f.ShowDialog).Start()
Now we should see the form appear again with a button on it. We can play with the button to make it bigger and brighter.
>>> b.Size = f.ClientSize
>>> b.BackColor = Color.Yellow
Let’s make the button do something interesting. In preparation for this we’re going to create a list of the named colors in the Color class. This is the one piece of code that includes the most Python specific code. If you’re unfamiliar with Python you should just treat most of this code as magic. Dive Into Python is a good first resource for an experienced programmer who wants to become familiar with Python. It also has a very short section on indentation of blocks in Python. To make this example work, the one thing you should be aware of is that for each line which begins with "..." you will need to type a TAB to create the correct indentation and get your program to run correctly.
>>> colors = []
>>> for name in dir(Color):
... c = getattr(Color, name) # Use TAB to indent this line and below
... if type(c) == Color: colors.append(c)
...
>>> colors
[Color [AliceBlue], Color [AntiqueWhite], Color [Aqua], Color [Aquamarine], Colo
<snip>
ke], Color [Yellow], Color [YellowGreen]]
Now that we have this list of colors, we can set the background color of the button to these colors in sequence. This requires creating a function to do the work and then setting that function to be run on the Click event. (Note: def is used in Python to define a new function, and just like above you should use TAB to indent each line in the body of the function.)
>>> index = 0
>>> def push(b, e):
... global index # Use TAB to indent this line and below
... b.BackColor = colors[index]
... b.Text = colors[index].Name
... index += 1
...
>>> b.Click += push
>>>
Click on the button to cycle through all of the named colors. Finally, we need to exit the interpreter. This is done with ‘Ctrl-Z’.
>>> ^Z
C:\IronPython\bin>
Now that we’re done playing with the interactive shell, we can put the results of our experiment into a file for running stand-alone. Now that we’re done experimenting, we can simplify the code a little bit by moving some of the property settings into the Form and Button constructors. We can also leave out all of the separate Thread nonsense and just call f.ShowDialog at the end of setting everything up.
------ colors.py ------
from System.Windows.Forms import *
from System.Drawing import *
f = Form(Text="Playing with colors", MinimizeBox=False, Size=Size(200,200))
b = Button(Text="Push Me", Size=f.ClientSize)
f.Controls.Add(b)
colors = []
for name in dir(Color):
c = getattr(Color, name)
if type(c) == Color: colors.append(c)
index = 0
def push(b, e):
global index
b.BackColor = colors[index]
b.Text = colors[index].Name
index += 1
b.Click += push
f.ShowDialog()
------
Now you can run this as a stand-alone program:
C:\IronPython\bin> IronPythonConsole colors.py
I hope that this has helpful to give newcomers a feel for what IronPython feels like to code in and to give even experienced Python programmers a few more concrete examples of how to work with the CLR. As one last recommendation to anyone new to IronPython, I’d like to pass on this advice overheard on the ironpython users mailing list. IronPython will sometimes look more like VB than C# in the way that it uses CLR libraries and you should look at both C# and VB examples if you’re confused about how to call something in IronPython.
Comments
- Anonymous
August 23, 2004
Looks like a lot of newlines got whacked :) - Anonymous
August 23, 2004
A quick comment concerning the threading problems: the "fix" used in this article is, of course, both simple and wrong, in the sense that it does not comply with the Windows Forms threading model. Specifically, only the thread that creates a control is allowed to access (methods or properties of) that control. Therefore, the f.ShowDialog calls are non-compliant.
Note: Once all of the separate Thread nonsense is left out, the code is compliant. - Anonymous
August 23, 2004
Your newline in the console session seem to be MIA. - Anonymous
August 23, 2004
Jim Hugunin has a weblog - Anonymous
August 23, 2004
Thanks for the formatting comments. I've at least partly fixed the issue and added comment to the start of the blog.
The threading issue is a more serious one, and not one that I can fix with a couple of edits. I'll still defend this example as showing a good model for the process of interactively exploring an API with an interactive interpreter. Notice that the end-result stand-alone program doesn't violate the threading model.
I know that GTK has similar complicated threading issues that make this kind of interactive use dificult in similar ways. I'm curious to play with the new Avalon GUI framework to see what its threading model is like. - Anonymous
August 23, 2004
Thanks for this great intro :) - Anonymous
August 23, 2004
I've been following IronPython for quite some time now. Personally, I think combining Python and the CLR is like a dream :-)
So, Jim, what other dynamic languages will you be working on? How much of a focus is Python in the Microsoft radar??
- Swaroop
www.python.g2swaroop.net
"A Byte of Python" - The Beginner's book on Python - Anonymous
August 23, 2004
This is very cool. If somebody were to add intellisense to the interpreter, this would be very very cool. :-) - Anonymous
August 24, 2004
The comment has been removed - Anonymous
August 24, 2004
The comment has been removed - Anonymous
August 24, 2004
The comment has been removed - Anonymous
August 24, 2004
The comment has been removed - Anonymous
August 24, 2004
Why not just use the modeless Form.Show instead of the modal Form.ShowDialog? - Anonymous
August 24, 2004
I've been playing with IronPython for a few months now and I must say, I love the rapid throw-together feel of IronPython. Looking forward to seeing what you come up with Jim. - Anonymous
August 24, 2004
I tried using Form.Show, but then I couldn't get the button to show up when I added it to the form. I'm guessing there's a message pump somewhere that I'm supposed to worry about, but I haven't taken the time to delve in. I welcome anyone who can show me the "correct" way to do something like the interactive example above. - Anonymous
August 24, 2004
ShowDialog() starts its own message pump, which is why your updates work. For the same to happen with Show(), you'll need to call Application.DoEvents() after each update.
Jim - Anonymous
August 25, 2004
IronPython - Anonymous
August 26, 2004
hi Jim,
IronPython does not implement PEP 227 yet. http://www.python.org/peps/pep-0227.html
Kojo - Anonymous
August 26, 2004
Jim Hugunin, the inventor of IronPython (Python for .NET) has got a blog and for his first post gives examples of using IronPython as an interactive scripting environment for .NET. I'd never really thought before about just how useful the... - Anonymous
August 26, 2004
Jim Hugunin, the inventor of IronPython (Python for .NET) has got a blog and for his first post gives examples of using IronPython as an interactive scripting environment for .NET. I'd never really thought before about just how useful the... - Anonymous
August 29, 2004
Looks great,But i need something different in our application. What i Really need is, on Click of that button, i need to run python command, for example 'print "hello"'.
Actually There is a
a) Textbox to type the command
b) Button to run the command(given in textbox)
c) Textarea to display the output of the result.
Please help me over it.
Thanks
Senthil Kumar - Anonymous
August 31, 2004
Thanks for the note. IronPython is still in an early stage and has a number of features left to be implemented before it will be fully compatible with Python 2.3. Nested scopes will obviously be implemented before a 1.0 release. There is no technical reason that nested scopes would be hard to implement on the CLR; however, there are a number of different possible designs to choose from and I'd like to have some time to experiment before settling on one. - Anonymous
August 31, 2004
It shouldn't be that hard to write a little C# code around the existing IronPython code to enable this. Take a look at these pictures for what I think is a really cool version of what you're asking for, but using a tablet PC - http://www.knowing.net/2004/08/30.aspx#a818 - Anonymous
August 31, 2004
I fail to see how the example demonstrates the properties of a dynamic language. A lot of languages that are not considered dynamic could be used for the example. - Anonymous
September 01, 2004
Jim, while you're working with other dynamic languages, you might want to speak to the Visual FoxPro team (klevy@microsoft.com). - Anonymous
September 03, 2004
To Paul:
I realize that a LOT of languages could be used to write the final stand-alone program shown here. However, I'm not aware of very many languages that could be used to build this gui in the interactive way described in the blog. Could you give me an example of a non-dynamic language that could do this? - Anonymous
September 06, 2004
I think that "boo"(http://boo.codehaus.org) will soon have an interactive mode. - Anonymous
September 11, 2004
Dear Jim:
I am a fresh man to IronPython.The sample in this post is so amazing. Wish IronPython better and better!
When I experience IronPython, I tried these code as below(under the interpreter):
>>> class FantasySoft:
... def hello(self):
... print "Hello,World!"
...
Interpreter throws System.Reflection.TargetException: Non-static field requires a target.
And these three lines code is OK under Python Interpreter.Why the exception is thrown? Whether I made some mistake? Thanks! - Anonymous
September 13, 2004
The comment has been removed - Anonymous
June 24, 2008
PingBack from http://micheal.beststoriesxxx.com/dynamicalsystempython.html