storing variable names in a list before they are used?

J

John Salerno

If I want to have a list like this:

[(first_name, 'First Name:'), (last_name, 'Last Name:').....]

where the first part of each tuple is a variable name and the second
part is a label for the user to see, such as a form like this:

First Name: ________
Last Name: ________

(the variables would store whatever information is entered in the text
boxes to the right of each label. I'm doing it this way so I can write a
loop to construct my GUI components).

how would I go about putting these variable names in a list? I know I
can't leave them as above, but if I put them in as a string, then how do
I later "transform" them into an actual variable for assign, such as:

first_name = widget.get_text()

Is there some kind of idiom that does this sort of work?

Thanks.
 
F

Farshid Lashkari

Hi John

John said:
how would I go about putting these variable names in a list? I know I
can't leave them as above, but if I put them in as a string, then how do
I later "transform" them into an actual variable for assign, such as:

first_name = widget.get_text()

Is there some kind of idiom that does this sort of work?

What scope do you want these variable names to show up in? For example,
if you want them to be defined in the global scope then you can do the
following:

name = 'first_name'

globals()[name] = widget.get_text()

print first_name


If you want these variables to be assigned to an object then you can use
setattr():


name = 'first_name'

setattr(obj,name,widget.get_text())

print obj.first_name


Hope this helps

-Farshid
 
J

jmdeschamps

John said:
If I want to have a list like this:

[(first_name, 'First Name:'), (last_name, 'Last Name:').....]

where the first part of each tuple is a variable name and the second
part is a label for the user to see, such as a form like this:

First Name: ________
Last Name: ________

(the variables would store whatever information is entered in the text
boxes to the right of each label. I'm doing it this way so I can write a
loop to construct my GUI components).

how would I go about putting these variable names in a list? I know I
can't leave them as above, but if I put them in as a string, then how do
I later "transform" them into an actual variable for assign, such as:

first_name = widget.get_text()

Is there some kind of idiom that does this sort of work?

Thanks.

Not sure but mmaybe this older post might help:
http://mail.python.org/pipermail/tutor/2005-January/035232.html

JM
 
A

Ant

John said:
If I want to have a list like this:

[(first_name, 'First Name:'), (last_name, 'Last Name:').....]

where the first part of each tuple is a variable name and the second ....
can't leave them as above, but if I put them in as a string, then how do
I later "transform" them into an actual variable for assign, such as:

first_name = widget.get_text()

A better way of doing it may be to use a dictionary thus:

name_map = {"First Name": None, "Last Name": None}

and then assign the value:

name_map["First Name"] = widget.get_text()

Or alternatively if you were adamant you wanted your original format:

firstname = [None]
lastname = [None]

[(firstname, 'First Name:'), (lastname, 'Last Name:')]

firstname[0] = widget.get_text()

But that's a bit of a hack.

The problem you are having here is a conceptual one: When you put a
variable name in a list or tuple, it isn't the *name* that's stored but
the actual value. I would think about using the dictionary version
above, or if things are getting more complicated, then create a class
to produce objects that contain the structure you want:

class FormField(object):
def __init__(self, name, text=None):
self.name = name
self.text = text

firstname = FormField("First Name", "Default Text")
lastname = FormField("Last Name")

fields = [firstname, lastname]

lastname.text = widget.get_text()

The same of course could be accompished using pairs or dictionaries
(e.g. firstname = {"name": "First Name", "text": "Default Text"};
lastname = {"name": "Last Name"} ), but I think that the class based
version self documents itself a bit better.
 
M

MonkeeSage

John said:
If I want to have a list like this:

[(first_name, 'First Name:'), (last_name, 'Last Name:').....]

Do you need the data to be ordered? If not, just use a dictionary:

d = {'First Name:': '', 'Last Name:': ''}
d['First Name:'] = 'Bob'
d['Last Name:'] = 'Smith'
print "Hi, I'm %s %s." % (d['First Name:'], d['Last Name:'])

If so, check out the ordered dictionary module [1]:

from odict import OrderedDict as odict
od = odict([('First Name:', ''), ('Last Name:', '')])
od['First Name:'] = 'James'
od['Last Name:'] = 'Bond'
for k,v in od.items():
print "%s => %s" % (k,v)

[1] http://www.voidspace.org.uk/python/odict.html

Regards,
Jordan
 
S

Steve Holden

John said:
If I want to have a list like this:

[(first_name, 'First Name:'), (last_name, 'Last Name:').....]

where the first part of each tuple is a variable name and the second
part is a label for the user to see, such as a form like this:

First Name: ________
Last Name: ________

(the variables would store whatever information is entered in the text
boxes to the right of each label. I'm doing it this way so I can write a
loop to construct my GUI components).

how would I go about putting these variable names in a list? I know I
can't leave them as above, but if I put them in as a string, then how do
I later "transform" them into an actual variable for assign, such as:

first_name = widget.get_text()

Is there some kind of idiom that does this sort of work?

Thanks.

There are ways you can do this, but the best advice is "don't". If you
are putting names into a Python namespace that aren't known in advance
then you also have to use similarly obscure techniques to access the
variables, and you are running the risk that your code will collide whit
a name of a variable already used in that namespace by your code.

What's wring with just using a dict to store the values against the
names? Dicts and namespaces have a lot of behaviour in common.

regard
Steve
 
J

John Salerno

John said:
(the variables would store whatever information is entered in the text
boxes to the right of each label. I'm doing it this way so I can write a
loop to construct my GUI components).

Thanks very much for the responses guys. I actually tried something
similar with a dictionary already, but then I discovered the obvious: I
need them in a certain order! :)

Here is what I want to do more specifically: I am creating a single
frame (wxPython terminology for a window) and the user will be able to
click a "New" button which will open a new tab in that frame (using the
wx.Notebook class). Each time a new tab is opened, it will contain a
form to fill out, with a label widget on the left ("First Name:") and a
text box control on the right (the underlines), like this:

First Name: ________
Last Name: ________
Job Title: ________
etc.
etc.



In wxPython, you can use "sizers" for layout control, and in this case
the FlexGridSizer is ideal. You just assign the above widgets to it in
this order: first label, first textbox, second label, second textbox, etc.

Instead of manually creating these widgets and adding all of them to the
sizer (and having to add or delete code later in case something changes)
I wanted to use some type of for loop to do it for me. This is easy for
creating and adding the labels, because I need no reference for them
later. But I will need a reference for the textboxes so I can later get
the data that is in them.

So my original question involved finding a way to assign a variable name
to the textboxes while they are being automatically created in a for
loop. This seems like something that is probably done quite often and
maybe I'm just not thinking of the proper idiom that is used.

Thanks!
 
D

Dennis Lee Bieber

In wxPython, you can use "sizers" for layout control, and in this case
the FlexGridSizer is ideal. You just assign the above widgets to it in
this order: first label, first textbox, second label, second textbox, etc.

Instead of manually creating these widgets and adding all of them to the
sizer (and having to add or delete code later in case something changes)
I wanted to use some type of for loop to do it for me. This is easy for
creating and adding the labels, because I need no reference for them
later. But I will need a reference for the textboxes so I can later get
the data that is in them.

So my original question involved finding a way to assign a variable name
to the textboxes while they are being automatically created in a for
loop. This seems like something that is probably done quite often and
maybe I'm just not thinking of the proper idiom that is used.
You've got two separate concerns here...

Ordering the Form on Creation
and
Accessing the Fields Later

Are your textboxes all assumed to be the same length? If so, all you
need on entry to the form creation is a list of field names (labels),
since a list is ordered.

What you may want OUT of the form creation is a dictionary keyed by
those field names with each bound to the textbox control that was
created.

<<<pseudocode>>>
def createRecordForm(fldList):
frmData = {}
#do whatever is needed to initialize the form and backdrop
for fld in fldList:
gui.createLabel(fld)
frmData[fld] = gui.createTextBox(...)
return frmData

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
D

Dennis Lee Bieber

Talking to myself -- 'tis amazing where a mind may wander whilst in
the shower
Are your textboxes all assumed to be the same length? If so, all you
need on entry to the form creation is a list of field names (labels),
since a list is ordered.

What you may want OUT of the form creation is a dictionary keyed by
those field names with each bound to the textbox control that was
created.
You could expand on the input list -- a list of tuples; say:

flds = [ ("field label", "field name", {keyword : attributes}),
("First Name", "fname", {}),
("Phone Number", "phone", {"Numeric" : True, "Length" : 10}) ]
<<<pseudocode>>>
def createRecordForm(fldList):
frmData = {}
#do whatever is needed to initialize the form and backdrop
for fld in fldList:
gui.createLabel(fld) gui.createLabel(fld[0])
frmData[fld] = gui.createTextBox(...)
frmData[fld[1]] = gui.createTextBox(..., **fld[2] )
return frmData

This would allow shorter keys for later use... Instead of:

.... = frm["First Name"].getValue()

it is just

.... = frm["fname"].getValue()
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Salerno

John said:
Here is what I want to do more specifically:

Ok, I'm sure you all get the idea by now, but here's a simpler way to
look at it:

Instead of

first_name = wx.TextCtrl(self)
last_name = wx.TextCtrl(self)
job_title = wx.TextCtrl(self)
etc.

and subsequently:

sizer.Add(first_name)
sizer.Add(last_name)
sizer.Add(job_title)
etc.

I want to do something like this:

for name in names:
name = wx.TextCtrl(self)
sizer.Add(name)

It's just that I don't know how to handle the "name" variable in the
"names" list.
 
D

Dennis Lee Bieber

Ok, I'm sure you all get the idea by now, but here's a simpler way to
look at it:

Instead of

first_name = wx.TextCtrl(self)
last_name = wx.TextCtrl(self)
job_title = wx.TextCtrl(self)
etc.

and subsequently:

sizer.Add(first_name)
sizer.Add(last_name)
sizer.Add(job_title)
etc.

I want to do something like this:

for name in names:
name = wx.TextCtrl(self)
sizer.Add(name)

It's just that I don't know how to handle the "name" variable in the
"names" list.

Short blunt answer... You Don't

Longer answer... "names" is a list of strings which can be used as
keys into a dictionary.

dct = {}
for name in names:
dct[name] = wx.TextCtrl(self)
sizer.Add(dct[name])
return dct #presuming the above was part of some generic
function

where

names = [ "first_name", "last_name", "job_title" ]


The only other scheme is for you to supply a list of mutable objects

class MyObject(object):
pass

first_name = MyObject()
last_name = MyObject()
job_title = MyObject()

names = [ first_name, last_name, job_title ]

AND you only manipulate the inside of the object (which is basically
doing the same thing as manipulating a dictionary)

for name in names:
name.textBox = wx.TextCtrl(self)
sizer.Add(name.textBox)

COMPARE to a direct dictionary equivalent:

first_name = {}
last_name = {}
job_title = {}

names = [ first_name, last_name, job_title ]

for name in names:
name["textBox"] = wx.TextCtrl(self)
sizer.Add(name["textBox"])

..........

The three variations: dictionary keyed by string "variable name";
"named" class instances with attribute reference to internals; "named"
dictionary with keyed reference to internals

print dct["first_name"].getValue() #
print first_name.textBox.getValue() #or whatever wx uses
print first_name["textBox"].getValue()#

Only the first version condenses the eventual form label with the
same string name; the other two require the label text to be supplied
via another mechanism:

class MyObject(object):
def __init__(self, label):
self.label = label

first_name = MyObject("First Name:")


first_name = { "label" : "First Name:" }
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Salerno

Dennis Lee Bieber wrote:

Longer answer... "names" is a list of strings which can be used as
keys into a dictionary.

Thanks for all that! I like the idea of a dictionary, so I might try
that, although it does seem to be overcomplicating things a bit (almost
by necessity, though, given what I want to do).

But I suppose it's still a better solution than manually creating every
widget and adding it to the sizer.
 
D

Dennis Lee Bieber

Thanks for all that! I like the idea of a dictionary, so I might try
that, although it does seem to be overcomplicating things a bit (almost
by necessity, though, given what I want to do).

But I suppose it's still a better solution than manually creating every
widget and adding it to the sizer.

Look toward the potential future... Wherein your entire GUI is
defined with something like XML. Basically you'd be parsing the XML into
some structure (of structures) in which the only real access to the data
requires looking up the substructure using some fixed identifier.

Have you ever seen the macro definitions generated by VC++ when
defining a form using the Visual Studio Drag&Drop? (VB6 is relatively
clean, compared to VC++) And, of course, VS D&D /is/ building each form
statically, and you want dynamic.

Many moons ago, and all forgotten by now, I had to build an
emulation of a Ramtek 9300 graphics display (640x480 interlaced, 10-bit
color table allowing for rapid "overlay" enable/disable via simply
rewriting the color table) using DECWindows/Xt... NO GUI BUILDER, hand
edit of the GUI description file, hand mapping of description objects to
C source code. (Add, on top of the X stuff, I was using GKS display
lists to handle the overlays).

An off the wall XML variant

<gui>
<form label="Employee" id="employee" modal="no">
<sizer type="grid">
<textbox label="First Name:" id="fname" width="60" />
<textbox label="Last Name:" id="lname" width="60" />
<textbox label="Phone:" id="phone" width="10"
numeric="true" />
</sizer>
</form>
....
</gui>

Expand on concept to add any ordering/positioning on the form...

guiForms = { "employee" : {"label" : "Employee",
"model" : False,
"sizer" : { "type" : "grid",
"fields" : [ ....


More likely, instead of storing all those text fields you'd have
classes for "form", "sizer", "textbox", etc. and you'd store an instance
of each:

guiForms = {}
tmpForm = Form(label="Employee", modal=False)
tmpSizer = Sizer(type="grid")
tmpSizer.addField(id="fname", TextBox(label="First Name:", ...) ...)
tmpForm.addSizer(tmpSizer)
guiForms["employee"] = tmpForm

Of course, all those labels, ids, etc. would not be literal strings,
but be items extracted from the XML
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Salerno

Dennis said:
Look toward the potential future... Wherein your entire GUI is
defined with something like XML. Basically you'd be parsing the XML into
some structure (of structures) in which the only real access to the data
requires looking up the substructure using some fixed identifier.

Yeah, this is supported by wxPython, but I don't fully understand it
yet. I also feel like if I start using XML before I really learn how to
hand-code all of this in wxPython, then I'm missing out on learning the
real basics of doing it myself.
 
H

Hendrik van Rooyen

Dennis Lee Bieber said:
Short blunt answer... You Don't

Longer, less blunt answer:

You could, if you wanted to, write:

errfile = "name_of_error_file_for_compile_statement"
expr = name+" = wx.TextCtrl(self)"
eval(compile(expr, errfile,'single'))

and the name that reads the same as the text string should be created.

To access it, you can then use:

sizer.Add(eval(name))

Example:

IDLE 1.1.3 ==== No Subprocess ====Traceback (most recent call last):
File "<pyshell#0>", line 1, in ?
banana
NameError: name 'banana' is not defined
*ducks behind asbestos shelter to hide from the predicted flames *

But Seriously - I think eval is good for just this kind of purpose - does what
was wanted, namely creating the variable with the same name as the content of a
string... - its also useful to access a variable if you have been given its name
in a string, instead of being passed the thing itself - then you don't need the
compile bit...

Caveat Emptor

- Hendrik
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top