dynamic class/module use? (like Java's forName)

Heiko Wundram heikowu at ceosg.de
Mon Jul 19 13:54:09 EDT 2004


Am Sonntag, 18. Juli 2004 20:52 schrieb Alex Hunsley:
> Interesting, I hadn't thought of using a dict.
> Using a dict would be better than 'if's, but would still require a
> central part of the code to know about all the actions!
> My way allows new classes to be presented and used without altering
> existing code.
> Also my method forces new actions to interface with 'central' code via
> the available official interface, rather than having new actions
> potentially put in the central code and hence have access to things
> directly (which isn't a good OO design).

What I always do when I'm in your position to have an extendable API is to 
create a Registry with which the possible actions can register, a general 
parsing engine, which just does a dictionary lookup on some word (the 
dictionary being maintained by the module which contains the Registry), and 
then calls of into the appropriate code. All other modules can also use the 
Registry.

Something like this:

====
Registry.py

pluginDict = {}

def registerPlugin(name,plugincallable):
  pluginDict[name] = plugincallable

def queryPlugin(name):
  return pluginDict[name]()

====
Plugins/__init__.py

pass

====
Plugins/Module1.py

import Registry

class Callable1(object):
  def __init__(self):
    print "Instantiating Callable1."

  def test_method(self,*args,**kwargs):
    print "In test_method."
    print args, kwargs

Registry.register("callable1",Callable1)

====
Plugins/Module2.py

import Registry

class Callable2(object):
  def __init__(self):
    print "Instantiating Callable2."

Registry.register("callable2",Callable2)

====
Plugins.py

import os

for fname in os.listdir("Plugins"):
  try:
    __import__("Plugins.%s" % fname[-3],globals(),locals(),[])
  except:
    print "Warning: Couldn't import plugin:", fname

====
Main.py

import Registry
import Plugins

mod1 = Registry.queryPlugin("callable1")
print mod1
mod2 = Registry.queryPlugin("callable2")
print mod2

====
ParseCommand.py

import Registry

command = "callable1.test_method test 123 how are you?"
cmd = command.split(" ")
mod, attr = cmd[0].split(".",1)
mod = Registry.queryPlugin(mod)
getattr(mod,attr)(*cmd[1:])


This code only requires you to put all plugin modules into the subdirectory 
Plugins of the main program directory, and could easily be extended by 
rewriting Plugins.py to accomodate on demand loading/reloading of plugins, 
etc. ParseCommand.py can also easily be made more "intelligent" concerning 
the parsing of the actual command-line.

Is this extensible enough? ;)

HTH!

Heiko.



More information about the Python-list mailing list