Class or Dictionary?


M

Martin De Kauwe

Il giorno 12/feb/2011, alle ore 00.45, Martin De Kauwe ha scritto:



Ok then I suggest configobj, less buggy and much more powerful than ConfigParser:http://www.voidspace.org.uk/python/configobj.html

(and included from python 2.7).
In this way you can also simply just carry around that dictionary, and it will be correctly
typed if you validate the input.

That is interesting however I am using python 2.6 so I guess I shall
have to stick as I am for the moment. I think the way I used it above
was quite straight forward? It seemed OK? What are the issues?
 
Ad

Advertisements

M

Martin De Kauwe

That is interesting however I am using python 2.6 so I guess I shall
have to stick as I am for the moment. I think the way I used it above
was quite straight forward? It seemed OK? What are the issues?

Ignore that I have just tested it (it works in 2.6), much better!
Thanks!!
 
T

Terry Reedy

The point of this posting was just to ask those that know, whether it
was a bad idea to use the class object in the way I had or was that
OK? And if I should have just used a dictionary, why?

Did you miss my suggestion to use a module rather than a class?
Modules do not have some of the disadvantages of classes listed by J. Nagle.
 
M

Martin De Kauwe

Did you miss my suggestion to use a module rather than a class?
Modules do not have some of the disadvantages of classes listed by J. Nagle.

Hi, sorry I did. I just re-read it, could you provide an example?
Sorry i am having a major mind blank this morning (I think this is
obvious!?). And it would meet all of the criteria outlined by John
Nagle?
 
D

Dan Stromberg

If you read my post more carefully and less defensively, you'll see that
nothing I said was *opposed* to the use of pylint, merely that pylint is
not a substitute of a good, thorough test suite.

Actually, I mentioned the value of pylint. Then you asked me if my
unit tests were broken.

What would you infer from such a question?
 
T

Terry Reedy

Hi, sorry I did. I just re-read it, could you provide an example?

I am not sure what you are asking. tkinter.contants is one example.
Sorry i am having a major mind blank this morning (I think this is
obvious!?). And it would meet all of the criteria outlined by John
Nagle?

A module will work fine if but only if you commit yourself to having all
keys be legal Python identifiers. But that is usually not a problem with
configuration values.
 
Ad

Advertisements

S

Steven D'Aprano

Actually, I mentioned the value of pylint. Then you asked me if my unit
tests were broken.

What would you infer from such a question?


That I believed that you are using pylint as a substitute for unit tests,
instead of in conjunction with unit tests.
 
M

Martin De Kauwe

I am not sure what you are asking. tkinter.contants is one example.


A module will work fine if but only if you commit yourself to having all
keys be legal Python identifiers. But that is usually not a problem with
configuration values.

I think I got it, did you mean something like this?


class Constants:

radius_of_earth = 6.37122E+6
days_as_yrs = 1.0 / 365.25
m2_as_ha = 1E-4 # metres squared as hectares
g_as_tonnes = 1E-6 # grammes as tonnes
kg_as_tonnes = 1E-3 # kg as tonnes
kg_as_g = 1E+3

def __init__(self):

self.radius_of_earth = self.__class__.radius_of_earth
self.days_as_yrs = self.__class__.days_as_yrs
self.m2_as_ha = self.__class__.m2_as_ha
self.g_as_tonnes = self.__class__.g_as_tonnes
self.kg_as_tonnes = self.__class__.kg_as_tonnes
self.kg_as_g = self.__class__.kg_as_g


usage something like

Something similar for the params?

thanks
 
M

Martin De Kauwe

I think I got it, did you mean something like this?

class Constants:

    radius_of_earth = 6.37122E+6
    days_as_yrs = 1.0 / 365.25
    m2_as_ha = 1E-4  # metres squared as hectares
    g_as_tonnes = 1E-6  # grammes as tonnes
    kg_as_tonnes = 1E-3  # kg as tonnes
    kg_as_g = 1E+3

    def __init__(self):

        self.radius_of_earth = self.__class__.radius_of_earth
        self.days_as_yrs = self.__class__.days_as_yrs
        self.m2_as_ha = self.__class__.m2_as_ha
        self.g_as_tonnes = self.__class__.g_as_tonnes
        self.kg_as_tonnes = self.__class__.kg_as_tonnes
        self.kg_as_g = self.__class__.kg_as_g

usage something like

Something similar for the params?

thanks

And then I guess define some default parameters and then use configobj
to parse a .INI file. Then adjust those parameters change in the .INI
file?

e.g.

from parameters import DefaultParameters as params
# d -> comes from .INI file
p = params()
for key, value in d.iteritems():
# change anything read from file
p.__dict__[key] = value

?
 
T

Terry Reedy

I think I got it, did you mean something like this?


class Constants:

radius_of_earth = 6.37122E+6
days_as_yrs = 1.0 / 365.25
m2_as_ha = 1E-4 # metres squared as hectares
g_as_tonnes = 1E-6 # grammes as tonnes
kg_as_tonnes = 1E-3 # kg as tonnes
kg_as_g = 1E+3

def __init__(self):

self.radius_of_earth = self.__class__.radius_of_earth
self.days_as_yrs = self.__class__.days_as_yrs
self.m2_as_ha = self.__class__.m2_as_ha
self.g_as_tonnes = self.__class__.g_as_tonnes
self.kg_as_tonnes = self.__class__.kg_as_tonnes
self.kg_as_g = self.__class__.kg_as_g


usage something like

No, simpler. No class statememt necessarily needed.

module constants
----------------

radius_of_earth = 6.37122E+6
days_as_yrs = 1.0 / 365.25
m2_as_ha = 1E-4 # metres squared as hectares
g_as_tonnes = 1E-6 # grammes as tonnes
kg_as_tonnes = 1E-3 # kg as tonnes
kg_as_g = 1E+3
# could also have code to load stuff from other files


usage
=====1000.0

Real example(3.141592653589793, 2.718281828459045)
 
M

Martin De Kauwe

No, simpler. No class statememt necessarily needed.

module constants
----------------

radius_of_earth = 6.37122E+6
days_as_yrs = 1.0 / 365.25
m2_as_ha = 1E-4  # metres squared as hectares
g_as_tonnes = 1E-6  # grammes as tonnes
kg_as_tonnes = 1E-3  # kg as tonnes
kg_as_g = 1E+3
# could also have code to load stuff from other files

usage
=====
 >>> import constants
 >>> constants.kg_as_g
1000.0

Real example
 >>> import math
 >>> math.pi, math.e
(3.141592653589793, 2.718281828459045)

Cool! Thanks this seems straight forward, however if I do it this way
then once I change it (i.e. after reading user param file) I can't
pass the changed version to another module can i? Or am I being
stupid? Unless I do it my way I think

import cons
is fine.

But if I call import cons in another module it would be back to 1000.
right? Whereas if I do it as a class I can pass the adjusted instance?
E.g.

from constants import Constants
c = Constants()

I can then change "c" and pass this around?

Apologies if I have got that totally wrong!
 
Ad

Advertisements

T

Terry Reedy

Cool! Thanks this seems straight forward, however if I do it this way
then once I change it (i.e. after reading user param file) I can't
pass the changed version to another module can i? Or am I being
stupid? Unless I do it my way I think

import cons

is fine.

But if I call import cons in another module it would be back to 1000.
right?

Wrong. There is one and only one module object, imported into (which
means bound to a name in) as many modules as you want. If you change an
attribute, it is changed for all. If you add attributes from any module,
they are added for all, regardless of whether or not they have already
imported it. No different from changing a list or dict with multiple names.

The math module is read only. User python-coded modules are read-write.
 
D

Dave Angel

Cool! Thanks this seems straight forward, however if I do it this way
then once I change it (i.e. after reading user param file) I can't
pass the changed version to another module can i? Or am I being
stupid? Unless I do it my way I think

import cons

is fine.

But if I call import cons in another module it would be back to 1000.
right? Whereas if I do it as a class I can pass the adjusted instance?
E.g.

from constants import Constants
c =onstants()

I can then change "c" and pass this around?

Apologies if I have got that totally wrong!

Yep, you've got it totally wrong. As long as your import is the kind
you show here, changes are persistent. Other modules that import cons
will get the one you modified, not re-execute the source.

If you had tried something like from cons import kg
then you'd have a separate local binding. So don't do that.

DaveA
 
M

Martin De Kauwe

Wrong. There is one and only one module object, imported into (which
means bound to a name in) as many modules as you want. If you change an
attribute, it is changed for all. If you add attributes from any module,
they are added for all, regardless of whether or not they have already
imported it. No different from changing a list or dict with multiple names.

The math module is read only. User python-coded modules are read-write.

OK thanks I'll go over what I have done as I must have done something
stupid as I thought I tested it earlier and couldn't get it to work
like you suggested. Broadly this is how I am using it (incase it is
obvious, although perhaps it just works and I need to recheck). Apart
from that thanks for the modules idea it is very simple and seems to
be working nicely in principle.

from other_model import OtherSubModel
class Model:

def __init__(self):

# included other external modules (i.e. in other files)
om = OtherSubModel()

def run(self):
# call other submodel and pass params
om.run(params)

and the other file would look something like this

class OtherSubModel:
def __init__(self):
#some stuff

def run(params):
 
M

Martin De Kauwe

What's om supposed to be?  You define a local variable in one method,
and try to use it in a different one ????

Perhaps you meant  self.om =

 > class OtherSubModel:
 >     def __init__(self):
 >         #some stuff
 >
 >     def run(params):

You're missing a self here in the formal parameter list.

DaveA

I was trying to write a smaller version of broadly what I think i am
doing, perhaps I am not implementing it correctly. I have one model
which I have coded as a class, there were a few parts which could be
used separately (sub-models). So I decided to make them separate
classes in separate files which I *thought* I could just join up into
one package at run time. This way I could also use these modules
separately.

So in the dummy example

the other file is imported

from other_model import OtherSubModel

amd om = OtherSubModel was me making an instance of it? And then when
I called the *run* part of this sub-model I was passing it the
parameter file. I am sensing I have this wrong?
 
M

Martin De Kauwe

I was trying to write a smaller version of broadly what I think i am
doing, perhaps I am not implementing it correctly. I have one model
which I have coded as a class, there were a few parts which could be
used separately (sub-models). So I decided to make them separate
classes in separate files which I *thought* I could just join up into
one package at run time. This way I could also use these modules
separately.

So in the dummy example

the other file is imported

from other_model import OtherSubModel

amd om = OtherSubModel was me making an instance of it? And then when
I called the *run* part of this sub-model I was passing it the
parameter file. I am sensing I have this wrong?

oh and yes i did mean self.om.run(params), sorry!
 
Ad

Advertisements

M

Martin De Kauwe

I managed to get it to work like it explained, apologies not sure what
I did wrong earlier, odd.

Anyway thanks a lot for all of the suggestions + help
 

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

Top