Concise idiom to initialize dictionaries

Discussion in 'Python' started by Frohnhofer, James, Nov 9, 2004.

  1. 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: python-list-bounces+james.frohnhofer=
    > [mailto:python-list-bounces+james.frohnhofer=]On
    > Behalf Of Dennis Lee Bieber
    > Sent: Tuesday, November 09, 2004 10:31 AM
    > To:
    > Subject: Re: Determining combination of bits
    >
    >
    > On Mon, 8 Nov 2004 21:18:36 -0800, "news.west.cox.net"
    > <> declaimed the following in comp.lang.python:
    >
    > > > 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)...
    >
    > --
    > > ============================================================== <
    > > | Wulfraed Dennis Lee Bieber KD6MOG <
    > > | Bestiaria Support Staff <
    > > ============================================================== <
    > > Home Page: <http://www.dm.net/~wulfraed/> <
    > > Overflow Page: <http://wlfraed.home.netcom.com/> <

    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >


    ==============================================================================
    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.
    ==============================================================================
     
    Frohnhofer, James, Nov 9, 2004
    #1
    1. Advertising

  2. Frohnhofer, James

    Larry Bates Guest

    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


    Frohnhofer, James wrote:
    > 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: python-list-bounces+james.frohnhofer=
    >>[mailto:python-list-bounces+james.frohnhofer=]On
    >>Behalf Of Dennis Lee Bieber
    >>Sent: Tuesday, November 09, 2004 10:31 AM
    >>To:
    >>Subject: Re: Determining combination of bits
    >>
    >>
    >>On Mon, 8 Nov 2004 21:18:36 -0800, "news.west.cox.net"
    >><> declaimed the following in comp.lang.python:
    >>
    >>
    >>>>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)...
    >>
    >>--
    >> > ============================================================== <
    >> > | Wulfraed Dennis Lee Bieber KD6MOG <
    >> > | Bestiaria Support Staff <
    >> > ============================================================== <
    >> > Home Page: <http://www.dm.net/~wulfraed/> <
    >> > Overflow Page: <http://wlfraed.home.netcom.com/> <

    >>--
    >>http://mail.python.org/mailman/listinfo/python-list
    >>

    >
    >
    > ==============================================================================
    > 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.
    > ==============================================================================
    >
     
    Larry Bates, Nov 9, 2004
    #2
    1. Advertising

  3. [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().

    >>> for c in 'abcdefghijklmnopqrstuvwxyz':

    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
     
    Raymond Hettinger, Nov 9, 2004
    #3
  4. Frohnhofer, James

    Peter Otten Guest

    Frohnhofer, James wrote:

    > 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 :)

    >>> class AllDicts:

    .... 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
     
    Peter Otten, Nov 9, 2004
    #4
  5. On Tue, 9 Nov 2004 16:40:48 -0000, "Frohnhofer, James" <> wrote:

    >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
     
    Bengt Richter, Nov 10, 2004
    #5
  6. 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)])
     
    bruno modulix, Nov 11, 2004
    #6
  7. Caleb Hattingh <caleb1 <at> telkomsa.net> writes:
    >
    > 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] =)

    >>> class AllDicts(object):

    .... 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
     
    Steven Bethard, Nov 11, 2004
    #7
  8. 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


    On Tue, 09 Nov 2004 20:12:15 +0100, Peter Otten <> wrote:

    >
    > Here is a bunch of dictionaries that spring into existence by what is
    > believed to be magic :)
    >
    >>>> class AllDicts:

    > ... 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
    >
     
    Caleb Hattingh, Nov 12, 2004
    #8
  9. 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

    On Thu, 11 Nov 2004 20:30:18 +0000 (UTC), Steven Bethard
    <> wrote:

    > Caleb Hattingh <caleb1 <at> telkomsa.net> writes:
    >>
    >> 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] =)
    >
    >>>> class AllDicts(object):

    > ... 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
    >
     
    Caleb Hattingh, Nov 12, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. darrel
    Replies:
    13
    Views:
    810
    darrel
    Mar 30, 2006
  2. Bruno Desthuilliers

    concise code (beginner)

    Bruno Desthuilliers, Sep 4, 2007, in forum: Python
    Replies:
    27
    Views:
    620
    Gabriel Genellina
    Sep 10, 2007
  3. lysdexia
    Replies:
    6
    Views:
    561
    John Machin
    Dec 2, 2007
  4. Brandon
    Replies:
    12
    Views:
    516
    Brandon
    Aug 15, 2008
  5. Dave

    Concise idiom sought

    Dave, Mar 25, 2006, in forum: Perl Misc
    Replies:
    24
    Views:
    371
    it_says_BALLS_on_your_forehead
    Mar 29, 2006
Loading...

Share This Page