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

A

Alex Hunsley

Does python provide a way to dynamically use modules and/or classes?
I'm thinking in the vein of Java's Class.forName.

As a pseudocode example, I'm looking for the following ability:


classIWantToInstantiate = "packagenamehere.classNameHere"

anInstanceOfThatClass = makeNewClassFromString(classIWantToInstantiate,
parameters[])

# now anInstanceOfThatClass refers to an instantied
# packagenamehere.classNameHere object!



thanks
alex
 
A

Alex Hunsley

Alex said:
Does python provide a way to dynamically use modules and/or classes?
I'm thinking in the vein of Java's Class.forName.

As a pseudocode example, I'm looking for the following ability:


classIWantToInstantiate = "packagenamehere.classNameHere"

anInstanceOfThatClass = makeNewClassFromString(classIWantToInstantiate,
parameters[])

# now anInstanceOfThatClass refers to an instantied
# packagenamehere.classNameHere object!



thanks
alex

Oops.. I goggled but not hard enough obviously! I found my answer on
google groups:

http://shorterlink.com/?N2HPGU

alex
 
R

Roy Smith

Alex Hunsley said:
Does python provide a way to dynamically use modules and/or classes?
I'm thinking in the vein of Java's Class.forName.

Just out of curiosity, why do you want to do that?

The google link you provided talked about eval and exec. My experience
is that when I first started using Python (about 7 years ago), I used
eval and exec a lot. Now, I can't remember the last time I ever wanted
to use either.

Can you give us an example of what you're trying to do? My guess,
having not yet seen it, is that there's probably a better way to do it
than what you're asking.
 
5

510046470588-0001

Roy Smith said:
Just out of curiosity, why do you want to do that?

in order to be more flexible,
allowing code to be integrated that is available
only at run time of the program

Klaus Schilling
 
C

Christos TZOTZIOY Georgiou

Does python provide a way to dynamically use modules and/or classes?
I'm thinking in the vein of Java's Class.forName.

[snip]

Have you already considered the 'new' module? If not, give it a try.
 
A

Alex Hunsley

Roy said:
Just out of curiosity, why do you want to do that?

The google link you provided talked about eval and exec. My experience
is that when I first started using Python (about 7 years ago), I used
eval and exec a lot. Now, I can't remember the last time I ever wanted
to use either.

Can you give us an example of what you're trying to do? My guess,
having not yet seen it, is that there's probably a better way to do it
than what you're asking.

Ok, the situation is that I am parsing a file that has "actions" (or
commands) embedded in it. Different actions cause different things to
happen to the file which is being preprocessed for something. Now, since
I will have many actions, and want my python to be extensible so other
users can add their own actions, rather than hard coding each action
like so:

if (actionString == "blah"):
blahThang = blah(constructor stuff)
blahThang.doSomething()
else if (actionString == "blah2"):
blahThang2 = blah2(constructor stuff)
blahThang2.doSomething()
else if (actionString == "blah3"):
blahThang3 = blah3(constructor stuff)
blahThang3.doSomething()
else if (actionString == "blah2"):
# etc etc

.... I can have a different python class (and hence source file) for each
action, and the code for launching an action becomes generic (i.e.
creates instance of the class based on the command string and calls
agreed methods on it). I prefer this to the altyernative of hardcoding
each action with an 'if', as above, and then getting another user who
wants to extend my project have to add yet another if clause as well as
some code.
Another advantage of this generic approach is that it encourages other
users extending my code to put actions in seperate files, one per
action, rather than adding 'magic' code into the above 'if' chaos.

Basically, modular actions is the idea!

I'd be keen to hear peoples thoughts on my approach.

thanks
alex
 
A

Alex Hunsley

Roy said:
Just out of curiosity, why do you want to do that?

p.s. to my last response:

I've just read Robert Brewer's reply, and to rephrase myself as I to
him: I'm trying to do the strategy pattern in a modular fashion. (i.e.
no big string of 'ifs' and hardcoded actions.)

alex
 
T

Terry Reedy

Alex Hunsley said:
if (actionString == "blah"):
blahThang = blah(constructor stuff)
blahThang.doSomething()
else if (actionString == "blah2"):
blahThang2 = blah2(constructor stuff)
blahThang2.doSomething()
else if (actionString == "blah3"):
blahThang3 = blah3(constructor stuff)
blahThang3.doSomething()
else if (actionString == "blah2"):
# etc etc

The Python idiom for something like the above is to use a dict instead of
if/else.
It is especially useful when you want to add alternatives at runtime.
Something like

actions = { 'blah':blah, 'blah2', blah2, 'blah3':blah3, ...}
# easily extended at runtime
....
actions[actionString](constructor_stuff).doSomething

Terry J. Reedy
 
P

Paul McGuire

Ok, the situation is that I am parsing a file that has "actions" (or
commands) embedded in it. Different actions cause different things to
happen to the file which is being preprocessed for something. Now, since
I will have many actions, and want my python to be extensible so other
users can add their own actions, rather than hard coding each action
like so:

if (actionString == "blah"):
blahThang = blah(constructor stuff)
blahThang.doSomething()
else if (actionString == "blah2"):
blahThang2 = blah2(constructor stuff)
blahThang2.doSomething()
else if (actionString == "blah3"):
blahThang3 = blah3(constructor stuff)
blahThang3.doSomething()
else if (actionString == "blah2"):
# etc etc
<snip>

Alex,

Have a look at how pyparsing (http://pyparsing.sourceforge.net) supports the
attachment of actions to parse expressions within a grammar.

-- Paul
 
A

Alex Hunsley

Terry said:
if (actionString == "blah"):
blahThang = blah(constructor stuff)
blahThang.doSomething()
else if (actionString == "blah2"):
blahThang2 = blah2(constructor stuff)
blahThang2.doSomething()
else if (actionString == "blah3"):
blahThang3 = blah3(constructor stuff)
blahThang3.doSomething()
else if (actionString == "blah2"):
# etc etc


The Python idiom for something like the above is to use a dict instead of
if/else.
It is especially useful when you want to add alternatives at runtime.
Something like

actions = { 'blah':blah, 'blah2', blah2, 'blah3':blah3, ...}
# easily extended at runtime
...
actions[actionString](constructor_stuff).doSomething

Terry J. Reedy

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).
 
C

Christopher T King

classIWantToInstantiate = "packagenamehere.classNameHere"

anInstanceOfThatClass = makeNewClassFromString(classIWantToInstantiate,
parameters[])

# now anInstanceOfThatClass refers to an instantied
# packagenamehere.classNameHere object!

getattr is probably the best way to go about this:

packagename,classname = classIWantToInstantiate.split('.')
myclass = getattr(locals()[packagename], classname)

Or, if you want to support nested classes:

classnames = classIWantToInstantiate.split('.')
myclass = locals()[classnames[0]]
for classname in classnames[1:]:
myclass = getattr(myclass, classname)

Then you can just instantiate the class with myclass().

(Question for those in the know: why isn't there a way you can reference
the current module, i.e. so getattr(current_module,something) would be
equivalent to locals()[something]?)
 
H

Heiko Wundram

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.
 
H

Heiko Wundram

Am Montag, 19. Juli 2004 19:54 schrieb Heiko Wundram:
...
Something like this:

Err, that code was untested, please substitute:
====
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)
+ Registry.registerPlugin("callable1",Callable1)
====
Plugins/Module2.py

import Registry

class Callable2(object):
def __init__(self):
print "Instantiating Callable2."
- Registry.register("callable2",Callable2)
+ Registry.registerPlugin("callable2",Callable2)

....

HTH!

Heiko.
 
H

Heiko Wundram

Am Montag, 19. Juli 2004 19:54 schrieb Heiko Wundram:
Something like this:

And another bug... Hmmm... I should never post code which I don't intend to
test in the interpreter...
====
ParseCommand.py

import Registry
+ import Plugins

....

Heiko.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top