Using dictionaries

Alex Martelli aleaxit at yahoo.com
Tue Dec 5 03:17:12 EST 2000


"sorular" <sorular at netscape.net> wrote in message
news:3a2c9264.503856587 at news-server.bigpond.net.au...
> G'day
>
> I am trying to write a python program where a "configuration.py" will
> have all the user entered values in a dictionary format and a
> "main.py" which will import these and use it as local parameters.
>
> But, there are quite a few values in the dictionary
> ie
> dict = { 'key1':'value1' , ' key2':'value2' , ......'keyN':'value2'}

So far, so good.  Some of the values could also be added
with a dict['otherkey']='othervalue' syntax, of course.  When
you "import configuration", both the dict's original definition
and the further additions/changes will be executed in order,
so we can assume that right after that configuration.dict has
all of the settings you require.


> and in the "main.py" these will be all renamed with the local names
> ie
> Val1 = dictionary.dict['key1']
> Val2 = dictionary.dict['key2']
> ....
> ValN = dictionary.dict['keyN']
> etc....

First, I assume you mean configuration.dict, unless for some
peculiar reason you've chosen to "import configuration as dictionary"
(but why would you do that?).

> But overall, I still have a large numbe of values (ValN) to list... !

What is the relationship, if any, between the names of the
variables such as Val2 and the names of the keys such as key2?

If there is no systematic relationship, then you do have to
list the whole correspondence one way or another, of course;
and the long series of assignments is one such way (or you
could have another dictionary, or list or tuple of pairs, etc,
etc, and iterate over that).

If the correspondence is systematic, such as the one that
appears to be implicit in the naming you have used above
(each key is named 'key'+suffix for some string suffix, and
the variable that must be set like that is named 'Val'+suffix),
then you have a much easier life, e.g:

    for keyname, keyvalue in configuration.dict.items():
        if keyname.startswith('key'):
            __dict__['Val'+keyname[3:]] = keyvalue

It's up to you what you want to do (if anything) with
dictionary keys that do NOT start with 'key' -- just
ignore them, print a warning, throw an exception, whatever.

> Q1- Is there a more efficient way to do this ? I thought about using a
> for loop but that didnt work....

The above for-loop will certainly work if the relationship
between keynames and variable names is as I posit it.  If
it's otherwise, the only difference is on how you compute
the variablename to be set in correspondence to a given key.


> Q2 - would it be possible only to list the parameters in first file
> (ie dictionary.py
> key1 = value1
> key2 = value2
> .....
> keyN = valueN
> )

Sure (but is it configuration.py as you said at the start,
which would seem a much better name, or dictionary.py as you
say now and would seem to imply by your other usages?) --
this way, you're setting up the configuration.__dict__
(or dictionary.__dict__, whatever) dictionary.  I.e., if
your module is this way, you can use the same loop as
above, just change the for-statement itself to:

    for keyname, keyvalue in configuration.__dict__.items():
        # body does not have to change!

> and inside main.py, do a simple import...
> import dictionary *
> so that key1 can be used inside main.py as a local parameter?

Local variables are another issue, but I think you mean
"module-global" here anyway.  Sure, if the correspondence
between keyname and variablename is simple identity, this
will also work.  But a renaming is often advisable, just
to avoid accidental clashes (where the user, editing
configuration.py, happens by mistake to set a variable
whose name equals some other identifier used in main.py),
and it's not much harder to perform (as long as it's in
some way _systematic_, not haphazard) than just sucking
everything in.

If you've not decided on a naming convention for keys in
configuration.py versus variables in main.py, I suggest
you choose a prefix (and ensure no other identifiers in
main.py start with that prefix), such as, say, conf_, and
do something like:
    for keyname, keyvalue in configuration.__dict__.items():
        if not keyname.startswith(prefix):
            keyname = prefix+keyname
        __dict__[keyname] = keyvalue

This lets the user write lines in configuration.py such
as:
    foo = 'bar'        # sets conf_foo for main.py
    conf_fee = 'fie'   # sets conf_fee ditto
and it's _almost_ equivalent to
    import configuration as conf
then using conf.foo, conf.fee, etc, instead of the
suggested conf_foo, conf_fee, etc; but it makes it
slightly easier to provide defaults in main.py for
configuration variables that the user has not set
otherwise in configuration.py, i.e. main.py could
start with something like:

conf_foo = 'a default for conf_foo'
conf_fee = 'another important default'
conf_fie = conf_fum = conf_bar = None    # common default
import configuration
# insert loop as above

then use the various conf_fie, conf_fee, etc etc, as
desired; they'd have their default values as set
before the import unless the user overrode them in
configuration.py.

If you'd rather use the conf.foo, conf.fee, etc,
syntax for this same purpose (and it would be
highly advisable in many ways most of the time),
it's also very easy to do so, for example:

class conf:
    foo = 'a default for conf.foo'
    fee = 'another important default'
    fie = fum = bar = None    # common default
    from configuration import *

assuming configuration.py only uses the plain
name and not conf_whatever.  Or, the class might
also easily use a finer degree of control with
an "import configuration", then a loop like the
above-exemplified ones.

Or you could use an instance object rather than
a class object, supposing for example you need
ALL conf.whatever variable to be None unless
explicitly set, the easiest way might be:

class Conf:
    foo = 'a default for conf.foo'
    fee = 'another important default'
    from configuration import *
    def __getattr__(self, name):
        return None
conf = Conf()

Now conf.foo and conf.fee are set by default as
above but can be overridden by lines such as
"foo = 'something else'" in configuration.py,
while ANY other conf.whatever is None unless set
in configuration.py.


As you can see, Python offers a lot of similar but not
identical approaches for the task you've set yourself.
It's not part of the party line, but, in Python, too,
there's more than one way to do it.  How to choose?  A
golden rule of programming is...:

    *Do the simplest thing that could possibly work*

Being aware of the nicest exotic possibilities is cool,
but don't use them unless the defects in SIMPLER ways
are actually giving you problems.  In other words,

    from configuration import *

might be the best solution (because it's simplest),
unless accidental name-clashes ARE actually a problem
you need to address, etc, etc.  (IMHO, the second
simplest approach is that of making conf a class
object, as above; the third-simplest, if a "default
default value" is actually useful in many cases, is
making conf an instance object, again as above; the
various loops explicitly manipulating __dict__ I see
as a little bit less simple, thus I would not tend
to use them in most cases -- unless I get convinced
that some simpler approach "can't possibly work" under
the specific conditions of a given problem).


Alex






More information about the Python-list mailing list