Concise idiom to initialize dictionaries

  • Thread starter Frohnhofer, James
  • Start date
F

Frohnhofer, James

My initial problem was to initialize a bunch of dictionaries at the start of a
function.

I did not want to do
def fn():
a = {}
b = {}
c = {}
. . .
z = {}
simply because it was ugly and wasted screen space.

First I tried:

for x in (a,b,c,d,e,f,g): x = {}

which didn't work (but frankly I didn't really expect it to.)
Then I tried:

for x in ('a','b','c','d','e','f','g'): locals()[x]={}

which did what I wanted, in the interpreter. When I put it inside a function,
it doesn't seem to work. If I print locals() from inside the function, I can
see them, and they appear to be fine, but the first time I try to access one
of them I get a "NameError: global name 'a' is not defined"

Now obviously I could easily avoid this problem by just initializing each
dictionary, but is there something wrong about my understanding of locals,
that my function isn't behaving the way I expect?


-----Original Message-----
From: [email protected]
[mailto:p[email protected]]On
Behalf Of Dennis Lee Bieber
Sent: Tuesday, November 09, 2004 10:31 AM
To: (e-mail address removed)
Subject: Re: Determining combination of bits


The dictionary was filled with arbitrary values, not
{ x : 2^x } values like you might have thought.

Well, you had stated "powers of two"... If all you wanted is a
bit mapping you could probably drop the dictionary and just use a list
of the values, indexed by the bit position, and my first attempt
logic...
It is actually more like {1:123, 2:664, 4:323, 8:990, 16:221... etc}

CheckBoxes = [ "FirstChoice",
"SecondChoice",
"ThirdChoice",
"FourthChoice",
"FifthChoice",
"SixthChoice" ]


for num in [22, 25, 9]:
bit = 0
while num:
if num & 1:
print CheckBoxes[bit],
bit = bit + 1
num = num >> 1
print

SecondChoice ThirdChoice FifthChoice
FirstChoice FourthChoice FifthChoice
FirstChoice FourthChoice

where "num" is the sum of the checkbox index values (or whatever
selection mechanism is used), assuming /they/ were set up in 2^(n+1)
scheme (n = bit position, starting with 0)...

--
============================================================== <
(e-mail address removed) | Wulfraed Dennis Lee Bieber KD6MOG <
(e-mail address removed) | Bestiaria Support Staff <
============================================================== <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

==============================================================================
This message is for the sole use of the intended recipient. If you received
this message in error please delete it and notify us. If this message was
misdirected, CSFB does not waive any confidentiality or privilege. CSFB
retains and monitors electronic communications sent through its network.
Instructions transmitted over this system are not binding on CSFB until they
are confirmed by us. Message transmission is not guaranteed to be secure.
==============================================================================
 
L

Larry Bates

It is almost certain that you should use either a list of dictionaries
or a dictionary containing other dictionaries for this. Creation of
26 distinct dictionaries is almost never a good solution as it makes
it nearly impossible to iterate over them and would make code to
manipulate them unable to be generalized easily.

Example:

#
# To create a list of dictionaries
#
list_of_dicts=[]
for i in range(26):
list_of_dicts.append({})

#
# Now you can reference each dictionary as:
#
# list_of_dicts[0], list_of_dicts[1], ...
#

or

import string
dict_of_dicts={}
for letter in string.ascii_lowercase:
dict_of_dicts[letter]={}

#
# Now you can reference each dictionary as:
#
# dict_of_dicts['a'], dict_of_dicts['b'], ...

Larry Bates


My initial problem was to initialize a bunch of dictionaries at the start of a
function.

I did not want to do
def fn():
a = {}
b = {}
c = {}
. . .
z = {}
simply because it was ugly and wasted screen space.

First I tried:

for x in (a,b,c,d,e,f,g): x = {}

which didn't work (but frankly I didn't really expect it to.)
Then I tried:

for x in ('a','b','c','d','e','f','g'): locals()[x]={}

which did what I wanted, in the interpreter. When I put it inside a function,
it doesn't seem to work. If I print locals() from inside the function, I can
see them, and they appear to be fine, but the first time I try to access one
of them I get a "NameError: global name 'a' is not defined"

Now obviously I could easily avoid this problem by just initializing each
dictionary, but is there something wrong about my understanding of locals,
that my function isn't behaving the way I expect?



-----Original Message-----
From: [email protected]
[mailto:p[email protected]]On
Behalf Of Dennis Lee Bieber
Sent: Tuesday, November 09, 2004 10:31 AM
To: (e-mail address removed)
Subject: Re: Determining combination of bits


Note: 2^1 = 2, so your dictionary is already in error...


The dictionary was filled with arbitrary values, not
{ x : 2^x } values like you might have thought.

Well, you had stated "powers of two"... If all you wanted is a
bit mapping you could probably drop the dictionary and just use a list
of the values, indexed by the bit position, and my first attempt
logic...

It is actually more like {1:123, 2:664, 4:323, 8:990, 16:221... etc}

CheckBoxes = [ "FirstChoice",
"SecondChoice",
"ThirdChoice",
"FourthChoice",
"FifthChoice",
"SixthChoice" ]


for num in [22, 25, 9]:
bit = 0
while num:
if num & 1:
print CheckBoxes[bit],
bit = bit + 1
num = num >> 1
print

SecondChoice ThirdChoice FifthChoice
FirstChoice FourthChoice FifthChoice
FirstChoice FourthChoice

where "num" is the sum of the checkbox index values (or whatever
selection mechanism is used), assuming /they/ were set up in 2^(n+1)
scheme (n = bit position, starting with 0)...

--
============================================================== <
(e-mail address removed) | Wulfraed Dennis Lee Bieber KD6MOG <
(e-mail address removed) | Bestiaria Support Staff <
============================================================== <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <


==============================================================================
This message is for the sole use of the intended recipient. If you received
this message in error please delete it and notify us. If this message was
misdirected, CSFB does not waive any confidentiality or privilege. CSFB
retains and monitors electronic communications sent through its network.
Instructions transmitted over this system are not binding on CSFB until they
are confirmed by us. Message transmission is not guaranteed to be secure.
==============================================================================
 
R

Raymond Hettinger

[Frohnhofer, James]
My initial problem was to initialize a bunch of dictionaries at the start of a
function.

I did not want to do
def fn():
a = {}
b = {}
c = {}
. . .
z = {}
simply because it was ugly and wasted screen space.

Use exec().
exec c + ' = {}'


Of course, as others have pointed out, the whole idea is likely misguided and
you would be better served with a list of unnamed dictionaries.


Raymond Hettinger
 
P

Peter Otten

My initial problem was to initialize a bunch of dictionaries at the start
of a function.

I did not want to do
def fn():
a = {}
b = {}
c = {}
. . .
z = {}
simply because it was ugly and wasted screen space.

Here is a bunch of dictionaries that spring into existence by what is
believed to be magic :)
.... def __getattr__(self, name):
.... d = {}
.... setattr(self, name, d)
.... return d
.... def __repr__(self):
.... items = self.__dict__.items()
.... items.sort()
.... return "\n".join(map("%s -> %r".__mod__, items))
....
ad = AllDicts()
ad.a[1] = 99
ad.b[2] = 42
ad.b[3] = 11
ad
a -> {1: 99}
b -> {2: 42, 3: 11}

Peter
 
B

Bengt Richter

My initial problem was to initialize a bunch of dictionaries at the start of a
function.

I did not want to do
def fn():
a = {}
b = {}
c = {}
. . .
z = {}
simply because it was ugly and wasted screen space.

First I tried:

for x in (a,b,c,d,e,f,g): x = {}

which didn't work (but frankly I didn't really expect it to.)
Then I tried:

for x in ('a','b','c','d','e','f','g'): locals()[x]={}

which did what I wanted, in the interpreter. When I put it inside a function,
it doesn't seem to work. If I print locals() from inside the function, I can
see them, and they appear to be fine, but the first time I try to access one
of them I get a "NameError: global name 'a' is not defined"

Now obviously I could easily avoid this problem by just initializing each
dictionary, but is there something wrong about my understanding of locals,
that my function isn't behaving the way I expect?
Others explained why locals()[x] worked interactively, and not in a function,
but if you just want a one-liner, you could just unpack a listcomp:
>>> a,b,c = [{} for i in xrange(3)]
>>> a,b,c
({}, {}, {})

If you have single-letter names, you can avoid the count by stepping through the letters:
>>> x,y,z = [{} for dont_care in 'xyz']
>>> x,y,z
({}, {}, {})

Or if you have a long target list and you can just type it and copy/paste it like:
>>> fee,fie,fo,fum,bim,bah = [{} for ignore in 'fee,fie,fo,fum,bim,bah'.split(',')]
>>> fee,fie,fo,fum,bim,bah ({}, {}, {}, {}, {}, {})
>>> map(id, (fee,fie,fo,fum,bim,bah))
[9440400, 9440976, 9438816, 9441120, 9440256, 9440544]


The dicts are separate, as you can see:
>>> id(a),id(b),id(c) (9153392, 9153248, 9439248)
>>> a,b,c = [{i:chr(i+ord('0'))} for i in xrange(3)]
>>> a,b,c
({0: '0'}, {1: '1'}, {2: '2'})

Regards,
Bengt Richter
 
B

bruno modulix

Larry Bates a écrit :
It is almost certain that you should use either a list of dictionaries
or a dictionary containing other dictionaries for this. Creation of
26 distinct dictionaries is almost never a good solution as it makes
it nearly impossible to iterate over them and would make code to
manipulate them unable to be generalized easily.

Example:

#
# To create a list of dictionaries
#
list_of_dicts=[]
for i in range(26):
list_of_dicts.append({})

or just
list_of_dicts = [{} for i in range(26)]

or if you want a dict of dicts :
dod = dict([(i, {}) for i in range(26)])
 
S

Steven Bethard

Caleb Hattingh said:
For interest sake, how would such a thing look with new-style classes? My
(likely misinformed) impression is that __getattr__ for example, doesn't
behave in quite the same way?

Just the same[1] =)
.... def __getattr__(self, name):
.... d = {}
.... setattr(self, name, d)
.... return d
.... def __repr__(self):
.... items = self.__dict__.items()
.... items.sort()
.... return '\n'.join(['%s -> %r' % item for item in items])
....
ad = AllDicts()
ad.a[1] = 99
ad.b[2] = 42
ad.b[3] = 11
ad
a -> {1: 99}
b -> {2: 42, 3: 11}
I believe that __getattr__ works just the same (but to check for yourself, see
http://docs.python.org/ref/attribute-access.html). I think what you're thinking
of is __getattribute__ which new-style classes offer *in addition* to
__getattr__. While __getattr__ is called only if an attribute is not found,
__getattribute__ is called unconditionally for every attribute access.

Steve

[1] modulo my preference for list comprehensions/generator expressions instead
of map
 
C

Caleb Hattingh

Peter, respect :)

For interest sake, how would such a thing look with new-style classes? My
(likely misinformed) impression is that __getattr__ for example, doesn't
behave in quite the same way?

thx
Caleb


Here is a bunch of dictionaries that spring into existence by what is
believed to be magic :)
... def __getattr__(self, name):
... d = {}
... setattr(self, name, d)
... return d
.. def __repr__(self):
... items = self.__dict__.items()
... items.sort()
... return "\n".join(map("%s -> %r".__mod__, items))
...
ad = AllDicts()
ad.a[1] = 99
ad.b[2] = 42
ad.b[3] = 11
ad
a -> {1: 99}
b -> {2: 42, 3: 11}

Peter
 
C

Caleb Hattingh

Steve,

Not only did you answer my silly question, but also the question I
actually wanted to ask ...__getattribute__ is what I was thinking of.

thats cool :)
thx
Caleb

Caleb Hattingh said:
For interest sake, how would such a thing look with new-style classes?
My
(likely misinformed) impression is that __getattr__ for example, doesn't
behave in quite the same way?

Just the same[1] =)
... def __getattr__(self, name):
... d = {}
... setattr(self, name, d)
... return d
... def __repr__(self):
... items = self.__dict__.items()
... items.sort()
... return '\n'.join(['%s -> %r' % item for item in items])
...
ad = AllDicts()
ad.a[1] = 99
ad.b[2] = 42
ad.b[3] = 11
ad
a -> {1: 99}
b -> {2: 42, 3: 11}
I believe that __getattr__ works just the same (but to check for
yourself, see
http://docs.python.org/ref/attribute-access.html). I think what you're
thinking
of is __getattribute__ which new-style classes offer *in addition* to
__getattr__. While __getattr__ is called only if an attribute is not
found,
__getattribute__ is called unconditionally for every attribute access.

Steve

[1] modulo my preference for list comprehensions/generator expressions
instead
of map
 

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,057
Latest member
KetoBeezACVGummies

Latest Threads

Top