Macro preprocessor.
Christian Tismer
tismer at appliedbiometrics.com
Fri Aug 13 05:01:24 EDT 1999
"Magnus L. Hetland" wrote:
>
> Christian Tismer <tismer at appliedbiometrics.com> writes:
>
> > Kaz Kylheku wrote:
> > [description of a cute macro processor skipped]
> >
> > > Okay, enough. :) I'll probably get hate mail now about being off topic.
> >
> > No hate mail, but some thoughts:
> [...]
>
> > There are a few cases where I admit that I generate scriptlets
> > on-the-fly using the formatting operator.
>
> Now you've piqued my interest... How do you do this, and in which
> cases (for what purposes)? Do you create strings that you execute, or
> what? (Sounds like a cool thing to do ;)
I wrote a helper class which fakes dynamic classes which
can be pickled and stored in database fields.
This was used for a glass fiber network simulation project, where
networks of nodes with lots of properties and direct or symbolic
references to other nodes have to be stored, edited and updated.
The first version of this used exec and formatting to generate
classes dynamically and provide attributes and methods.
Later I could replace almost everything with calls to the "new"
module, and dynnamic assignment of functions as methods.
This is a case where classes and instances are not so sharply
distinguished, it falls into the class of problems where
metaclasses are handy. One simulation defines a special
configuration, gathers data and is saved as an object in
the database, this makes it like an instance. But other
simulations can refer to it, use it as a building block
and inherit from it, which makes it look like a class.
This is a proprietary project, so I can show just some
excerpts from an outdated version of the source files.
System design has been completely redefined, so this is
history.
Here is a dynamic module generator:
----------------------------------------------------------------
#######################################################
# provide a virtual module which has no true file
DYN_MODULE_NAME = "dynamic node classes"
def __virtual_setup():
import new, sys
vm = new.module(DYN_MODULE_NAME)
sys.modules[DYN_MODULE_NAME] = vm
__virtual_setup()
del __virtual_setup
DYN_MODULE = __import__(DYN_MODULE_NAME)
# an alternative could be to replace the standard __import__
# function with one that can behave as expected.
# Anyway, this works.
class NodeGenerator: # Generates *no* code to declare a new class
on-the-fly
def __init__(self, base, tag):
import new
self.nodeLabel = cname = base + "_" + tag # name of the class to
generate
self.classDef = cl = new.classobj(cname, (globals()[base],), {})
def __init__(self, id):
self.__class__.__bases__[0].__init__(self,id)
# which has a slight semantical difference. Guess about it!
cl.__init__ = __init__ # function becomes an unbound method
cl.name = tag
# Initialize empty parameter and port defs
cl.parameterDefs = {}
cl.portDefs = {}
# provide a virtual module name
cl.__module__ = DYN_MODULE_NAME
def address (self, addr):
# Record the persistent address that the class has
self.classDef.address = addr
def defParameter (self, name, type, default, unit, range, desc):
# Record a parameter definition
param = {}
param[ "type" ] = type
param[ "default" ] = default
param[ "unit" ] = unit
param[ "range" ] = range
param[ "desc" ] = desc
self.classDef.parameterDefs[ name ] = param
def defPort (self, name, type, direction, cardinality, desc):
# Record a port definition
port = {}
port[ "type" ] = type
port[ "direction" ] = direction
port[ "cardinality" ] = cardinality
port[ "desc" ] = desc
self.classDef.portDefs[ name ] = port
def declareNode(self):
# just return the ready thing
return self.classDef
#######################################################
----------------------------------------------------------------
and here a factory for abstract nodes:
----------------------------------------------------------------
class AbstractNodeFactory:
def __init__(self):
self.knownNodes = {} # The known types of AbstractNodes keyed by
addresses
def getNode(self, address):
# Is the desired node known?
if address not in self.knownNodes.keys():
# No => generate on-the-fly
generator = NodeGenerator( "AbstractNode", "SomeShortLabel_"
+ address )
# Some dummy stuff
generator.address( address )
generator.defParameter( "Weight", "float", "42.0", "lbs",
"41.9-42.1", "The weight of the brain" )
generator.defPort( "Eye", "optical", "input", "2", "Optical
input" )
generator.defPort( "Ear", "acustical", "input", "2",
"Acustical input" )
generator.defPort( "Mouth", "acustical", "output", "1",
"Acustical output" )
# Declare the class and get to know it
generator.declareNode()
self.knownNodes[ address ] = generator.classDef # was
generatedClass
# store in the dynamic module as well
node = self.knownNodes[ address ]
setattr(DYN_MODULE, node.__name__, node)
# keep a reference to the factory instance as well
node.Factory = self
# Return the class object
return self.knownNodes[ address ]
# pickling support.
# we don't store the generated classes, but the parameters
# needed to restore them.
# therefore, the __getstate__/__setstate__ method
# avoid to make use of the __dict__
def __getstate__(self):
return self.knownNodes.keys()
def __setstate__(self, state):
self.__init__()
map(self.getNode, state)
class persistency:
"""wrap a node instance suitable for pickling"""
def __init__(self, node_inst):
factories = {}
instances = {} # maybe we must use id() in the future
todo = [node_inst]
while todo:
lookat = todo[0]
del todo[0]
for port in lookat.ports.values():
for conn in port.values():
inst = conn[0]
if not instances.has_key(inst):
todo.append(inst)
instances[inst] = 1
factories[inst.Factory] = 1
self.factories = factories.keys()
self.instances = instances.keys()
self.saveset = (self.factories, node_inst)
def __getstate__(self):
return self.saveset
def __setstate__(self, state):
factories, instance = state
self.__init__(instance)
#######################################################
--
Christian Tismer :^) <mailto:tismer at appliedbiometrics.com>
Applied Biometrics GmbH : Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101 : *Starship* http://starship.python.net
10553 Berlin : PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF
we're tired of banana software - shipped green, ripens at home
More information about the Python-list
mailing list