views:

139

answers:

4

For example in Lua you can place the following line at the end of a script:

return <some-value/object>

The value/object that is returned can then be retrieved by the hosting application.

I use this pattern so that scripts can represent factories for event handlers. The script-based event handlers are then used to extend the application. For example the hosting application runs a script called 'SomeEventHandler.lua' which defines and returns an object that is an event handler for 'SomeEvent' in your application.

Can this be done in Python? Or is there a better way to achieve this?

More specifically I am embedding IronPython in my C# application and am looking for a way to instance these script-based event handlers which will allow the application to be extended using Python.

+2  A: 

It's totally possible and a common technique when embedding Python. This article shows the basics, as does this page. The core function is PyObject_CallObject() which calls code written in Python, from C.

unwind
+3  A: 

This can be done in Python just the same way. You can require the plugin to provide a getHandler() function / method that returns the event handler:

class myPlugin(object):

  def doIt(self,event,*args):
    print "Doing important stuff"

  def getHandler(self,document):
    print "Initializing plugin"
    self._doc = document
    return doIt

When the user says "I want to use plugin X now," you know which function to call. If the plugin is not only to be called after a direct command, but also on certain events (like e.g. loading a graphics element), you can also provide the plugin author with possibilities to bind the handler to this very event.

balpha
How do you reference the function? The thing I really like in Lua about returning an object from the script is that the object is completely anonymous. You don't have to have some class name or global variable name that both the script and hosting application must agree on.
Ashley Davis
A python script (i.e. module) can't return an object. So you have to agree on some interface convention, be it "the plugin script must leave exactly one object in the namespace, and this must be an instance of MyApplicationPlugin," or it must provide a function of a particular name, or the like.
balpha
+1  A: 

The way I would do it (and the way I've seen it done) is have a function for each event all packed into one module (or across several, doesn't matter), and then call the function through C/C++/C# and use its return value.

musicfreak
+2  A: 

See some examples in Embedding the Dynamic Language Runtime.

A simple example, setting-and-fetching-variables:

SourceCodeKind st = SourceCodeKind.Statements;
string source = "print 'Hello World'";
script = eng.CreateScriptSourceFromString(source, st);
scope = eng.CreateScope();
script.Execute(scope);
// The namespace holds the variables that the code creates in the process of executing it.
int value = 3;
scope.SetVariable("name", value);

script.Execute(scope);

int result = scope.GetVariable<int>("name");
gimel