Newbie help- Can multiple instances with multiple namesautomatically created.

N

Nav

I have a class of let's say empty bottle which can have a mix of two
items. I want to create let's say 30 of these objects which will have
names based on the 2 attributes (apple juice, beer, grape juice, beer,
etc) that I provide from a list. All the objects are a mix of (1 of
three alcohols) and (1 of 10 juices), so
I don't want to go through typing in the names of all the objects
(which would be totally stupid).
I get problems if I try such as I can't assign to literal etc.
If I make a list of names using the attributes. then equate names to
objects. the list gets populated by the objects and the names
disappear.
I want the ability to be able to call up any object by its name and
manipulate it and yet not have to assign the name manually. How can
this be done?
 
S

Shawn Milochik

You could put them in a dictionary with the key being the name, instead of a list.

Shawn
 
C

Chris Rebert

You could put them in a dictionary with the key being the name, instead of a list.

To illustrate that for the OP:

name2drink = {}
for booze in liquors:
for juice in juices:
name = juice +" "+booze # or however you're naming them
drink = Bottle(booze, juice)
name2drink[name] = drink

#example use
favorite = name2drink["apple wine"]
favorite.rating = 9/10

Cheers,
Chris
 
J

Jan Kaliszewski

name2drink = {}
for booze in liquors:
for juice in juices:
name = juice +" "+booze # or however you're naming them
drink = Bottle(booze, juice)
name2drink[name] = drink

@Nav: ...and if you really desire to have those objects in global
(module's) namespace, you can do that:

global_namespace = globals()
for booze in liquors:
for juice in juices:
name = '{0}_with_{1}_juice'.format(booze, juice)
drink = Bottle(booze, juice)
global_namespace[name] = drink

# then you have them in module's namespace
print(wine_with_apple)
wine_with_apple.rating = 0.9

Though in most cases it'd be not necessary.

Cheers,
*j

PS. Another way to express practically the same:

from itertools import product

globals().update(('{0}_with_{1}_juice'.format(booze, juice),
Bottle(booze, juice))
for booze, juice in product(liquors, juices))
 
N

Nav

You could put them in a dictionary with the key being the name, instead of a list.

To illustrate that for the OP:

name2drink = {}
for booze in liquors:
    for juice in juices:
        name = juice +" "+booze # or however you're naming them
        drink = Bottle(booze, juice)
        name2drink[name] = drink

#example use
favorite = name2drink["apple wine"]
favorite.rating = 9/10

typing
favorite = such and such is what I am trying to avoid.

I want to be able to use the name 'apple_wine' as the variable which
has the object apple wine but not have to do this manually as you did
with favorite.
 
S

Shawn Milochik

You could put them in a dictionary with the key being the name, instead of a list.

To illustrate that for the OP:

name2drink = {}
for booze in liquors:
for juice in juices:
name = juice +" "+booze # or however you're naming them
drink = Bottle(booze, juice)
name2drink[name] = drink

#example use
favorite = name2drink["apple wine"]
favorite.rating = 9/10

typing
favorite = such and such is what I am trying to avoid.

I want to be able to use the name 'apple_wine' as the variable which
has the object apple wine but not have to do this manually as you did
with favorite.

Then don't assign a variable to favorite, and just use name2drink["apple wine"].
 
S

Steve Holden

Nav said:
You could put them in a dictionary with the key being the name, instead of a list.
To illustrate that for the OP:

name2drink = {}
for booze in liquors:
for juice in juices:
name = juice +" "+booze # or however you're naming them
drink = Bottle(booze, juice)
name2drink[name] = drink

#example use
favorite = name2drink["apple wine"]
favorite.rating = 9/10

typing
favorite = such and such is what I am trying to avoid.

I want to be able to use the name 'apple_wine' as the variable which
has the object apple wine but not have to do this manually as you did
with favorite.
Why? The example is trying to show you that it's much more sensible
(i.e. better controlled, easier to manage, less likely to cause
problems) if instead of looking up the names in the global namespace you
instead looked them up in a dictionary.

This question arises so frequently it should really be a FAQ, but the
closest I can come is

http://techblog.ironfroggy.com/2007/06/dynamic-hell.html

which does at least exercise the necessary arguments.

regards
Steve
 
N

Nav

Thanks Jan,
You read my mind. That is exactly what I needed.
Thanks for showing the product function from itertools as well. It
seems easier to grasp than the nested loops, I had been using.
I noticed chopin.edu.pl. Are you a musician?
Nav
 
N

Nav

Thanks for pointing it out Steve. The blog post doesn't explain it
very well. I understand the risk of exec or eval(input). but what are
the risks of globalnamespace use and what are the benefits?
 
N

Nav

Okay, let me ask another question:

When we create instances of objects by doing
x = className ()
are we using globalnamespace?

if yes then:
if using globalnamespace is bad then why does every book or tutorial
about python classes give the above style of assignment as an
example?

Second why do we use a dictionary to create something like this? I
know how it works, but what is wrong with simply creating instances
automatically? Once created the data for the instances is
automatically saved in their own space? Why have a round about way
using dictionaries?
Is there an advantage or does it conflict with something else?

Why not have
for i in specialList: #I presume it would have to be special, because
it can't be a problematic type
i = className(whatever)
 
S

Steven D'Aprano

Okay, let me ask another question:

When we create instances of objects by doing
x = className()
are we using globalnamespace?

That depends on whether you are doing x = className() inside a function
(or class), or in the top level of the program.


If I do this:

x = 1234

def function():
y = 4567

then x is defined in the global namespace and y is defined in the
namespace which is local to function().

if yes then:
if using globalnamespace is bad then why does every book or tutorial
about python classes give the above style of assignment as an example?

No, you're confused -- the problem isn't with using the global namespace.
The problem is that you don't know what names you want to use ahead of
time.

You use assignment like:

x = something()

when you know the name x when you are writing the code. That way you can
write x in the code, and all is good:

x = something()
print x.method()
mydict = {x: -1}
assert mydict.keys() == [x]

Now, imagine that you didn't know what names you have to use. Say, for
example, that you need a variable number of Somethings:

a = Something()
b = Something()
c = Something()
d = Something()
# I never know when to stop...
z = Something()
# ... keep going? too far? who knows??? HELP!
process(a)
process(b)
process(c)
# when do I stop???
process(x)
process(y) # ...


That's the wrong way to deal with it. So instead you use a list:


mylist = [] # define ONE NAME in the global namespace
for i in range(some_number):
mylist.append(Something())
# later...
for x in mylist: # again, we use ONE name, `x`
process(x)



A list implicitly maps numbers (the position) to values. If you want to
map strings (names) to values, use a dict. Here is an example. Notice we
don't know how many players there are, or what their names are:


print "Welcome to the game."
print "Please enter the name of each player,"
print "or the word 'STOP' when there are no more players."
players = {}
i = 1
while True:
# loop forever
name = raw_input("Name of player %d? " % i)
name = name.strip() # get rid of extra whitespace
if name.upper() == 'STOP':
# we're done
break
players[name] = NewPlayer()

# much later...
for name, player in players.items():
print "Welcome, player %s" % name
play_game(player)


The only downside is that dicts are unordered, so the order of the
players is not the same as the order they were entered in.
 
A

alex23

When we create instances of objects by doing
x = className ()
are we using globalnamespace?

Well, you're using a namespace, which namespaces its in would depend
on the scope in which that assignment occurred. And there's not really
a global namespace, only module ones.
if yes then:
  if using globalnamespace is bad then why does every book or tutorial
about python classes give the above  style of assignment as an
example?

That's a basic assignment example. It's not a direct manipulation of
globals(), like the solution given by Jan, which you seem to feel is
the answer. And unless it happens outside of a nested scope like a
class or function definition, it's not 'global'.
Second why do we use a dictionary to create something like this? I
know how it works, but what is wrong with simply creating instances
automatically?

If I came across code like this in a joint project I was working on:

def somefunc(*someparams):
magical_instance_injection()
for elem in magically_appearing_collection:
....

We'd have serious words about the readability & maintainability of
such code.

If the values are important, make a clear set up that places them in a
mapped collection, and make it obvious that the collection is how
those values are used.

Also, you've removed the set up from the place where the values are
actually used, meaning I'd have to look at two sets of code to
identify the values' names, as well as to confirm that
'some_random_label' _is_ actually one of the instances and not just a
value you're using without instantiating.
Once created the data for the instances is
automatically saved in their own space? Why have a round about way
using dictionaries?

Because using a dictionary removes the dependency your function has on
the injection code, which in turns makes it more flexible for re-use.

Let's assume you write your injection function, and call it within
every function that uses those objects:

def inject_values():
# here be global() manipulations

def do_that_thang():
inject_values()
...

What if you want to do_that_thang to a separate set of values? With
this approach, you'd have to extend like so:

def inject_values2():
...

def do_that_thang2():
inject_values2()
...

You could, of course, have one inject_values function that accepts a
flag and returns the appropriate set of values, but now you're having
to modify that function every time the values change.

With a dictionary, it's just so much simpler:

values1 = dict(
a = SomeObject(1),
b = AnotherObject(1)...
)

values2 = dict(
a = SomeObject(2),
b = AnotherObject(2)...
)

def do_that_thang(values):
c = values['a'].thanger(values['b'])
...

It's clean, readable and far more easily extensible. It's also far
more obvious what you're doing, which you'll really appreciate when
you return to the code in a year's time :)
 
N

Nav

"> if yes then:
if using globalnamespace is bad then why does every book or tutorial
about python classes give the above style of assignment as an
example?

That's a basic assignment example. It's not a direct manipulation of
globals(), like the solution given by Jan, which you seem to feel is
the answer. And unless it happens outside of a nested scope like a
class or function definition, it's not 'global'. "

Thanks for clearing that up Alex. The reason I liked Jan's solution at
first glance was that it allowed me to manipulate the objects directly
after I created the class. But I am using Shawn's advice now because
it lets me abstract, but still allows me to directly manipulate the
object if I need to.

@ Steven....
"No, you're confused -- the problem isn't with using the global
namespace.
The problem is that you don't know what names you want to use ahead of
time. "

Actually I know what the names would be and how I want to use them.
If you look at my example in the beginning you will notice that it
creates unique objects with unique names, which anyone who looks at
what is being mixed can easily figure out and of course the number and
names of objects is directly dependent on the mixed elements.
(although perhaps bottle is not the best analogy because the contents
can change, which will not change once the object is created.)
Having a stable and descriptive naming strategy was important,
especially to use the unique object directly, and to not have to go
searching where they might be located at any moment, e.g. if they are
being moved about as part of other data structures. If anyone has any
other thoughts regarding this, I would appreciate them.

- Thanks everyone.
 
D

Dave Angel

(You top-posted. It's polite on most newsgroups, and specifically on
this one to add your comments *following* the quoted earlier text)
Okay, let me ask another question:

When we create instances of objects by doing
x = className ()
are we using globalnamespace?
If that line appears at top-level, it uses the global namespace for the
symbol x. If it's inside a class, or inside a function, then it uses
some other namespace. The risk for globals is mainly that the namespace
gets "polluted", or full of unrelated symbols, which sooner or later are
going to collide. And this is made much worse if someone is creating
such names indirectly, by monkeying with the non-portable constructs
such as global(), or by doing from mymodule import * There are
other risks, but this is a short message.

As far as I know, there's very little performance cost for having lots
of stuff in globals. It's just bad practice because it frequently leads
to bugs.
if yes then:
if using globalnamespace is bad then why does every book or tutorial
about python classes give the above style of assignment as an
example?
Beginner books keep things simple. Besides the same statement is great
if it's in a function. And it's usually a small step for the beginner
to start moving stuff from the top-level of the module into named
functions. And eventually to functions that are small enough to be
maintainable.
Second why do we use a dictionary to create something like this? I
know how it works, but what is wrong with simply creating instances
automatically? Once created the data for the instances is
automatically saved in their own space? Why have a round about way
using dictionaries?
Is there an advantage or does it conflict with something else?
What? Automatically where? What's roundabout about dictionaries?
Why not have
for i in specialList: #I presume it would have to be special, because
it can't be a problematic type
i = className(whatever)
Once you bind a new value to i, it no longer has any relationship to the
value which was in specialList. Perhaps you want something like:
for i in xrange(len(specialList)):
specialList = className(...)

which will replace the present values in specialList with instances of
className.
 
S

Steven D'Aprano

@ Steven....
"No, you're confused -- the problem isn't with using the global
namespace.
The problem is that you don't know what names you want to use ahead of
time. "

Actually I know what the names would be and how I want to use them.

You said earlier:

"I have a class of let's say empty bottle which can have a mix of two
items. I want to create let's say 30 of these objects which will have
names based on the 2 attributes (apple juice, beer, grape juice, beer,
etc) that I provide from a list."

Your description is confusing to me. What on earth is an empty bottle
which has a mix of two items in it? Surely that means it's not empty any
more? But putting that aside:


"All the objects are a mix of (1 of three alcohols) and (1 of 10
juices), so I don't want to go through typing in the names of all the
objects (which would be totally stupid)."

Right... so your problem isn't that you don't know what the variable
names is, but there are too many to comfortably enumerate in the source
code.

The answer is, again, avoid named variables. Instead of (say):

gin_apple_strawberry = Bottle('gin', 'apple')
gin_apple_orange = Bottle('gin', 'orange')
# etc.

again you should use a list or dict:

bottles = []
for alcohol in ('gin', 'beer', 'wine'):
for fruit in ('apple', 'banana', 'blueberry',
'strawberry', 'orange', 'peach'):
bottles.append(Bottle(alcohol, fruit))
for bottle in bottles:
process(bottle)
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top