Create object name from string value?

G

Gnarlodious

I want to declare several objects from names in a list:

objects=['object1', 'object2', 'object3', 'object4']
for objectName in objects:
objectName=classname()

That fails, and so do these:

exec(objectName)=classname()
eval(objectName)=classname()

So how to make an object whose name is the value in the variable?

-- Gnarlie
 
G

Gnarlodious

Since (I presume) you are a newcomer to Python, it's best to learn the
common style <URL:http://www.python.org/dev/peps/pep-0008/>.
Thanks for that.
This is almost certainly better done with a dictionary. Like so::

    object_names = ['object1', 'object2', 'object3', 'object4']
    objects = {}
    for object_name in object_names:
        objects[object_name] = Class()

And thanks for that too. I see it returns a list of objects, Python is
very cool.

-- Gnarlie
 
S

Steven D'Aprano

I want to declare several objects from names in a list:

objects=['object1', 'object2', 'object3', 'object4'] for objectName in
objects:
objectName=classname()


That's the wrong way to handle the problem. Named objects are only useful
if you know the name of the object when writing the code. Otherwise, how
do you know what name to use in the code?

That fails, and so do these:

exec(objectName)=classname()
eval(objectName)=classname()


The right way to solve this problem is with a dictionary:

for name in ["object1", "object2", "object3"]:
d = {name: classname()}
print d[name]



but for the record, the way to use exec is like this:

exec("object1 = classname()")

But beware, exec is not only much slower than the alternatives, but it
risks putting a serious security flaw in your software. As a general
rule, 9 times out of 10 if you think you want exec, you don't.
 
G

Gnarlodious

That's the wrong way to handle the problem. Named objects are only useful
if you know the name of the object when writing the code. Otherwise, how
do you know what name to use in the code?

Thank you for the help. I am gathering the names of all *.plist files
in a folder, creating objects named the filename, and accessing the
data like this:

Data.Server.Config.BaseURL

Adding a .plist file would automatically create a plist dictionary
object inside the Data module.
The right way to solve this problem is with a dictionary:

for name in ["object1", "object2", "object3"]:
    d = {name: classname()}
    print d[name]

This works! However I end up saying:

d['Server'].Config.BaseURL

to get the data, when I should be saying:

Server.Config.BaseURL
but for the record, the way to use exec is like this:

exec("object1 = classname()")

I failed to make that work. So back to the original question. How to
make an instance named according to a string inside a variable? I
guess it should be in the top-level namespace, not inside a list or
dictionary.

-- Gnarlie
http://Gnarlodious.com/Gnarlodious
 
A

Alf P. Steinbach

* Gnarlodious:
That's the wrong way to handle the problem. Named objects are only useful
if you know the name of the object when writing the code. Otherwise, how
do you know what name to use in the code?

Thank you for the help. I am gathering the names of all *.plist files
in a folder, creating objects named the filename, and accessing the
data like this:

Data.Server.Config.BaseURL

Adding a .plist file would automatically create a plist dictionary
object inside the Data module.
The right way to solve this problem is with a dictionary:

for name in ["object1", "object2", "object3"]:
d = {name: classname()}
print d[name]

This works! However I end up saying:

d['Server'].Config.BaseURL

to get the data, when I should be saying:

Server.Config.BaseURL
but for the record, the way to use exec is like this:

exec("object1 = classname()")

I failed to make that work. So back to the original question. How to
make an instance named according to a string inside a variable? I
guess it should be in the top-level namespace, not inside a list or
dictionary.

I don't understand how you intend to use a variable whose name comes from
dynamic data.

So I agree with Steven that it's the wrong way to handle the problem --
whatever the problem is!

But, if it can help:



Cheers,

- Alf
 
T

Tim Chase

Gnarlodious said:
for name in ["object1", "object2", "object3"]:
d = {name: classname()}
print d[name]

This works! However I end up saying:

d['Server'].Config.BaseURL

to get the data, when I should be saying:

Server.Config.BaseURL

It sounds like you want a mapping of strings to class objects
(not instances), so you can do something like

mapping = {
"object1": object1,
"object2": some_module.object2,
"object3": other_module.namespace.object3,
}

MyClass = mapping["object1"]
server = MyClass(initialization_params)
# the above two lines can be written as
# server = mapping["object1"](init_params)
print server.Config.BaseURL


-tkc
 
A

Adam Tauno Williams

D

Dave Angel

Gnarlodious said:
That's the wrong way to handle the problem. Named objects are only useful
if you know the name of the object when writing the code. Otherwise, how
do you know what name to use in the code?

Thank you for the help. I am gathering the names of all *.plist files
in a folder, creating objects named the filename, and accessing the
data like this:

Data.Server.Config.BaseURL

Adding a .plist file would automatically create a plist dictionary
object inside the Data module.

The right way to solve this problem is with a dictionary:

for name in ["object1", "object2", "object3"]:
d =name: classname()}
print d[name]

This works! However I end up saying:

d['Server'].Config.BaseURL

to get the data, when I should be saying:

Server.Config.BaseURL

but for the record, the way to use exec is like this:

exec("object1 =lassname()")

I failed to make that work. So back to the original question. How to
make an instance named according to a string inside a variable? I
guess it should be in the top-level namespace, not inside a list or
dictionary.

-- Gnarlie
http://Gnarlodious.com/Gnarlodious
I know you figure you have a specific list of files, and that they'll
never conflict with the other global variables you've defined. But
adding globals dynamically is "magic", and can lead to very obscure
bugs. Suppose sometime in the future somebody adds another plist file
with the same name as one of your functions?

Put it inside a dummy class, as follows:

That avoids the ["Server"] syntax, but still doesn't risk polluting your
global namespace with arbitrary names. And in the example above, you'd
be using
plists.Server.Config.BaseURL


And if you must use the global namespace, you can simply do:
>>> globals()["Server"] = 42
>>> Server
42

DaveA
 
S

Steven D'Aprano

The right way to solve this problem is with a dictionary:

for name in ["object1", "object2", "object3"]:
    d = {name: classname()}
    print d[name]

This works! However I end up saying:

d['Server'].Config.BaseURL

to get the data, when I should be saying:

Server.Config.BaseURL


There are three moments in time that the programmer needs to care about:
when you write the code, when you compile the code, and when you run the
code. In this case, the two relevant ones are write-time and run-time.

If you expect to be able to write

Server.Config.BaseURL

then that means that you MUST know the name "Server" at write-time.
(Otherwise, how do you know to write "Server", instead of "MyServer" or
"ServerSix"?) That means that the *name* Server isn't specified at
runtime, but at write-time. Since you already know the name, then the
right solution is to do something like:

Server = classname()

and then refer to Server, just like you would do:

x = 45
print x+1

or similar.

But if you are getting the name "Server" from a config file at runtime,
say something like this:

name=Server
class=classname
flag=True

then you can't write:

Server.Config.BaseURL

in your source code, because you don't know if it will be called
"Server", or "MyServer" or "Server42", or "WebServe", or "Fred". In
general, you don't even know how many servers there will be: there could
be one, or none, or fifty. So you need a level of indirection, hence the
dictionary.
 
G

Gnarlodious

Put it inside a dummy class, as follows:

This has been very educational, thank you for all the suggestions.
Here is the resulting code:


class Property: pass # example of a dummy class
Plist = Property() # create a Plist object from the dummy class

# accumulate dictionary attributes based on every plist file
dataFolder=os.path.dirname(__file__)+'/Data/'
plistFiles=glob.glob(dataFolder+'*.plist')

for file in range(len(plistFiles)):
name=plistFiles[file].replace(dataFolder,'').replace('.plist','')
setattr(Plist, name, Dict(plistFiles[file]).Config) # load the Plist
object with the dictionary



This is a vast improvement over my previous system. Now I can call any
plist item from anywhere on my website:

Data.Plist.Site.Trace

where "Site.plist" is the name of the Plist file. This is such an
elegant system I'm surprised it is not implemented as part of Python.

-- Gnarlie
http://Gnarlodious.com/Gnarlodious
 

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,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top