using names before they're defined

B

Bruno Desthuilliers

brings me onto another question that has been bugging me, which is, if
I want to create components (as object instances) at run time (rather
than through a python code imported in), how do I do this? i.e. if I
hardcoded something like
turbine1 = turbine(...)
then python knows that turbine1 is a turbine. but if I had say some
kind of user interface and I want to create turbine1 (or suchlike) on
the fly, how do I actually do that? how do I create objects after run
time?

Q&D possible solution, no error handling, etc
....just so you get an idea

# schema generated by a GUI
# or directly written in a .py config file
# or whatever

schema = {'turbine1': {'class': 'Turbine',
'upstream' : ('frobnicator2',),
'downstream' : () # nothing,
},
'frobnicator2' : {'class' : 'Frobnicator',
'upstream' : (),
'downstream' : ('frobnicator2',),
},
}

# code:

def get_class_by_name(name):
return globals()[name]

def chain_from_schema(schema):
objects = {}
for name, desc in schema:
klass = get_class_by_name(desc['class'])
objects[name] = klass()
for name, desc in schema:
target = objects[name]
ups = [objects[upname] for upname in desc['upstream']]
downs = [objects[downname] for downname in desc['downstream']]
target.links(upstream=ups, downstream=downs)
return objects
 
D

davehowey

Hiya

Could you just talk me through this... is it:
schema = {'turbine1': {'class': 'Turbine',
'upstream' : ('frobnicator2',),
'downstream' : () # nothing,
},
'frobnicator2' : {'class' : 'Frobnicator',
'upstream' : (),
'downstream' : ('frobnicator2',),
},
}

ok, so schema is a dictionary of different components, defining what
class they are and what they're connected to.
def get_class_by_name(name):
return globals()[name]

what does this function do exactly?
def chain_from_schema(schema):
objects = {} # so objects is our list of objects ?
for name, desc in schema: # can you step through a dictionary like this?
klass = get_class_by_name(desc['class']) # does this create an object called klass?
objects[name] = klass()


sorry for being dim..
Dave
 
L

Larry Bates

I don't know if you saw my earlier post but something like
this has worked for me.

What about something like:

supply = supply()
compressor = compressor(supply)
combuster1= combuster(compressor)
combuster2= combuster(compressor)
compressor.append(combuster1)
compressor.append(combuster2)

or perhaps

compressor.extend([combuster1, combuster2])


turbine = turbine(combuster)
combuster.append(turbine)


If you implement .append and .extend methods
on your classes they will allow you to append single
downstream objects or extend with a list of them.
Just keep a list self.downstream and append/extend
it. IMHO it makes what is going on intuitively obvious.

-Larry Bates
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
Hiya

Could you just talk me through this... is it:




ok, so schema is a dictionary of different components, defining what
class they are and what they're connected to.

Yeps.

Note that it could as well be a list of tuple or anything like this, ie:
schema = [
('turbine1', 'Turbine', ('frobnicator2',), ()),
('frobnicator2', 'Frobnicator', (), ('frobnicator2',),
]

I choose a dict for readability.

Also, I gave the example using Python code as 'config' format, but any
structured enough text format could do, ie JSON, XML, or even ini-like:

# schema.ini
objects = turbine1, frobnicator2

[turbine1]
class=Turbine
upstream=frobnicator2
downstream=

[frobnicator2]
class=Frobnicator
upstream=
downstream=turbine


Now you just read the file with the standard config parser and build
your chain from it... (implementation left as an exercice...)

def get_class_by_name(name):
return globals()[name]


what does this function do exactly?

Q&D way to retrieve the class object (Python's classes are themselves
objects) known by it's name (as a string).

globals() returns the module's namespace as a dict object with
'name':eek:bject pairs. This code assume that the name is available in the
current module's namespace, but could be improved to handle needed
imports etc.
# can you step through a dictionary like this?

Nope, sorry, it's a mistake I do over and over. It's of course:;
for name, desc in schema.items():

(note that you can iterate over a dict's keys with 'for k in thedict:' )
klass = get_class_by_name(desc['class'])
# does this create an object called klass?

Nope, it binds the class object (retrieved by get_class_by_name()) to
the local name 'klass' ('class' is a reserved name).
objects[name] = klass()

sorry for being dim..

Where ?
 
D

davehowey

Hi
Also, I gave the example using Python code as 'config' format, but any
structured enough text format could do, ie JSON, XML, or even ini-like:

# schema.ini
objects = turbine1, frobnicator2

[turbine1]
class=Turbine
upstream=frobnicator2
downstream=

yes, I like the idea of using .ini type file format or XML, very much.
There are parser available which will automatically building python
objects from this, won't they (like configparser)? I'll have to get
reading over the weekend...
def get_class_by_name(name):
return globals()[name]

Q&D way to retrieve the class object (Python's classes are themselves
objects) known by it's name (as a string).

ok, so it actually returns the class object itself.
One thing that confuses me is that objects have a name (self.name) but
object instances also have a name (e.g. myspecialturbine = turbine(...)
---- how do I discover the name 'myspecialturbine' ?). And object
instances have a class name too ('turbine'). Aaargh, too many names!
what if just want to know what the name of the instance is (in this
case 'myspecialturbine'?)

Right. I'll have a go at pulling all this together over the weekend
hopefully. Hurrah! Thanks for all the help, to everyone.
Dave
 
B

Bruno Desthuilliers

Hi

(snip)
def get_class_by_name(name):
return globals()[name]
Q&D way to retrieve the class object (Python's classes are themselves
objects) known by it's name (as a string).


ok, so it actually returns the class object itself.
One thing that confuses me is that objects have a name (self.name)

They dont - unless you give them one:
Traceback (most recent call last):
Traceback (most recent call last):

classes, functions and modules have a __name__ attribute, but that's
something else...
but
object instances also have a name (e.g. myspecialturbine = turbine(...)

Actually, this is the other way round: names refers ('are bound to')
objects. Think of namespaces (the global or local one...) as dicts
holding name:ref-to-object pairs (that's mostly what they are FWIW).
Different names can refer to the same object. The object itself doesn't
know anything about this.
---- how do I discover the name 'myspecialturbine' ?).

From within the object refered by this name ? Short answer : you can't.
And object
instances have a class name too ('turbine').

Nope, they have a class, which itself as a __name__ attribute, which is
the name that was used when "creating" the class object (ie: usually
when the 'class' statement is eval'd at module load time).
Aaargh, too many names!
what if just want to know what the name of the instance is (in this
case 'myspecialturbine'?)

you just named it so yourself, ie:
myspecialturbine = SpecialTurbine()

Else, no way. You can of course give a name when instanciating the object:

class Named(object):
def __init__(self, name):
self.name = name

n1 = Named('n1')
print n1.name
=> n1

But this doesn't mean there's any correspondance between this name and a
name in the current (or any other) namespace:

toto = n1
n1 = "lalala"
print toto.name
=> n1

locals()[toto.name] is toto
=> False
 
N

Nick Vatamaniuc

Dave,

Sometimes generating classes from .ini or XML files is not the best
way. You are just translating one language into another and are making
bigger headaches for your self. It is certainly cool and bragable to
say that "my classes get generated on the fly from XML" but Python is
terse and reasonable enough to just write it in Python. In other words
instead of saying <turbine> <power>2MW</power></turbine> just write
some Python code that instantiates a turbine with a 2MW power based on
your class. Then you can evaluate Python code in Python and you even
got your on-the-fly generation.
As a general rule, I would say to think 3 times before touching XML in
Python unless you are absolutely forced to. Config .ini files can be
more acceptable but Python is still best. Why write
;;My turbine class
[turbine]
power=2MW
speed=800rpm
....
when you can just say:
#my turbine class
t=Turbine( power="2MW", \
speed="800rpm", \
...
First case is a little shorter but then you have to use a parser for it
while in the second case you just execute the file, and besides, you
can edit it with any Python editor.

Hope this helps,
Nick V.


Hi
Also, I gave the example using Python code as 'config' format, but any
structured enough text format could do, ie JSON, XML, or even ini-like:

# schema.ini
objects = turbine1, frobnicator2

[turbine1]
class=Turbine
upstream=frobnicator2
downstream=

yes, I like the idea of using .ini type file format or XML, very much.
There are parser available which will automatically building python
objects from this, won't they (like configparser)? I'll have to get
reading over the weekend...
def get_class_by_name(name):
return globals()[name]

Q&D way to retrieve the class object (Python's classes are themselves
objects) known by it's name (as a string).

ok, so it actually returns the class object itself.
One thing that confuses me is that objects have a name (self.name) but
object instances also have a name (e.g. myspecialturbine = turbine(...)
---- how do I discover the name 'myspecialturbine' ?). And object
instances have a class name too ('turbine'). Aaargh, too many names!
what if just want to know what the name of the instance is (in this
case 'myspecialturbine'?)

Right. I'll have a go at pulling all this together over the weekend
hopefully. Hurrah! Thanks for all the help, to everyone.
Dave
 
P

Patrick Maupin

I have a problem. I'm writing a simulation program with a number of
mechanical components represented as objects. When I create instances
of objects, I need to reference (link) each object to the objects
upstream and downstream of it, i.e.

supply = supply()
compressor = compressor(downstream=combustor, upstream=supply)
combuster = combuster(downstream=turbine, upstream=compressor)
etc.

the problem with this is that I reference 'combustor' before is it
created. If I swap the 2nd and 3rd lines I get the same problem
(compressor is referenced before creation).


aargh!!! any ideas on getting around this?

Dave

I have done similar things in the past. One useful trick is to define
a special class for connections, create a single instance of this
class, and make all your connections as attributes of this instance.
For example:

world = Simulation()

world.supply = Supply()
world.compressor = Compressor(downstream=world.cumbustor,
upstream=world.supply)
world.cumbuster = Combuster(downstream=world.turbine,
upstream=world.compressor)

Because Python lets you control attribute access to your simulation
world object, it is relatively easy to make proxy objects for
attributes which don't yet exist via __getattr__, and then to insert
the real object into the proxy via __setattr__.

Alternatively, the script (using the same syntax as shown above!) can
simply collect all the connection information when it is run, then make
a "real" structure later. This works best if your simulation objects
(Supply, Compressor, Cumbuster) allow setting of the connection
attributes after instantiation.

Regards,
Pat
 
B

Bruno Desthuilliers

Nick said:
Dave,

Sometimes generating classes from .ini or XML files is not the best
way. You are just translating one language into another and are making
bigger headaches for your self. It is certainly cool and bragable to
say that "my classes get generated on the fly from XML" but Python is
terse and reasonable enough to just write it in Python. In other words
instead of saying <turbine> <power>2MW</power></turbine> just write
some Python code that instantiates a turbine with a 2MW power based on
your class. Then you can evaluate Python code in Python and you even
got your on-the-fly generation.
As a general rule, I would say to think 3 times before touching XML in
Python unless you are absolutely forced to. Config .ini files can be
more acceptable but Python is still best. Why write
;;My turbine class
[turbine]
power=2MW
speed=800rpm
...
when you can just say:
#my turbine class
t=Turbine( power="2MW", \
speed="800rpm", \
...
First case is a little shorter but then you have to use a parser for it

There's one builtin.
while in the second case you just execute the file, and besides, you
can edit it with any Python editor.

This is certainly nice when the users are able to write python code, but
that's not always the case. Also, it can be dangerous to directly
execute user's python code...
 
D

davehowey

First case is a little shorter but then you have to use a parser for it
There's one builtin.

do you mean 'configparser'? I'm just trying to figure out how this
works. Does it generate objects from the config file automatically?

Dave
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
do you mean 'configparser'?
Yes.

I'm just trying to figure out how this
works.

One nice thing with Python is the interactive python shell. It makes
exploring a package a breeze.
Does it generate objects from the config file automatically?

It generates a representation of the config file as a Python object
composed of sections and options. The documentation should get you started.
 
D

David Isaac

Suppose I have inherited the structure

PackageFolder/
__init__.py
mod1.py
SubPackageFolder/
__init__.py
mod2.py
mod3.py

When mod1 is run as a script,
I desire to import either mod2 or mod3 but not both
conditional on an option detected by the 'main()' function
in mod1.

Whichever is imported will be imported as, say, 'use_mod',
and code in mod1 will refer to use_mod.

Problem:
classes in mod1 that refer to 'use_mod' of course
raise a NameError, since the import does not take
place until 'main()' is run.

So, what is the right way to implement my desire?

Thanks,
Alan Isaac
 
D

davehowey

Yes, I know it. But I don't like it. Either a simple ini file do the
trick, or I need a full blown app-specific DSL - which can be as simple
as a Python file with dicts, lists, etc !-)

What do you mean? I don't really understand. I had a blast with
configobj and seems to be ok - quite straightfoward for the type of ini
file I'm using. configparser prob the same... it's kind of 'much over
muchness' as they say

Dave
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
What do you mean? I don't really understand.

It's not a criticism of configobj - which is a quite nice package -,
it's just a matter of personal tastes (I don't like configobj's
[[[some-nested-sub-sub-section]]] syntax) and specific needs.

Most of the time, I don't need nothing more than a plain ini file - and
in this case, I prefer to use configparser because it's in the standard
lib (so I avoid a dependency on a 3rd part package).

When an ini file won't do, it's usually because what the app need is
really complex and specific enough to justify a "domain specific language".

And sometimes, this DSL can be expressed with Python's syntax, like for
example:

schema = {'turbine1': {'class': 'Turbine',
'upstream' : ('frobnicator2',),
'downstream' : () # nothing,
},
'frobnicator2' : {'class' : 'Frobnicator',
'upstream' : (),
'downstream' : ('frobnicator2',),
},
}

FWIW, the package's end user is not even supposed to know this is in
fact Python code !-)

FWIW, JSON can be a good candidate for this kind of stuff too.
 

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,014
Latest member
BiancaFix3

Latest Threads

Top