Is it better to use class variables or pass parameters?

Discussion in 'Python' started by Derek Basch, Mar 1, 2006.

  1. Derek Basch

    Derek Basch Guest

    This one has always bugged me. Is it better to just slap a "self" in
    front of any variable that will be used by more than one class method
    or should I pass around variable between the methods?

    Flamewar........NOW!

    jk, I really do want other opinions.

    Thanks,
    Derek
    Derek Basch, Mar 1, 2006
    #1
    1. Advertising

  2. Derek Basch

    Mc Osten Guest

    On 1 Mar 2006 11:32:02 -0800, Derek Basch wrote:

    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method
    > or should I pass around variable between the methods?


    I think there is no clear "general" answer. A criterion could be that
    instance variables should be those who define the state of the object, that
    define its "meaning".

    About the others to me it's a matter of taste.

    --
    USB Priests for only 10$
    Mc Osten, Mar 1, 2006
    #2
    1. Advertising

  3. On Wed, 1 Mar 2006, Derek Basch wrote:

    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method
    > or should I pass around variable between the methods?


    As a general rule, I only turn a parameter into an instance variable when
    it would otherwise be a parameter of all (or nearly all) methods. Though
    this is perhaps an overly mechanical perspective, I like to think of
    instance variables as implicit parameters to every method. It helps me
    keep scope under control and encourages better cohesion.

    --
    .:[ dave benjamin -( ramen/sp00 )- http://spoomusic.com/ ]:.
    "one man's constant is another man's variable" - alan perlis
    Dave Benjamin, Mar 1, 2006
    #3
  4. On Wed, 01 Mar 2006 11:32:02 -0800, Derek Basch wrote:

    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method
    > or should I pass around variable between the methods?


    That depends on whether the variable is conceptually an attribute of the
    instance or a parameter.

    Attributes of the instance should be made instance attributes by (as you
    put it) slapping a "self" in front of it. Parameters of the methods should
    be passed around as arguments to the methods.


    --
    Steven.
    Steven D'Aprano, Mar 1, 2006
    #4
  5. On 1 Mar 2006 11:32:02 -0800
    "Derek Basch" <> wrote:
    > This one has always bugged me. Is it better to just slap a
    > "self" in front of any variable that will be used by more
    > than one class method or should I pass around variable
    > between the methods?


    My first reaction was that they should always be object
    properties -- that passing values between methods of the
    same object is always a bad idea. But on further reflection,
    I'm not sure that's really the rule I use, so here's a
    better attempt:

    Are the values in question properties of the object?

    If I make two calls to the object from unrelated processes,
    should those values be the same, or different for each
    caller?

    If they need to be different for each caller, then you might
    need to pass them around. If however, they are the same
    because it's the same object, then they ought to be
    expressed as properties of the object.

    It's funny, I've never actually had any doubts about
    which to use in practice, it always seems obvious, so
    it's hard to recall what my actual thought process is
    on the subject.

    --
    Terry Hancock ()
    Anansi Spaceworks http://www.AnansiSpaceworks.com
    Terry Hancock, Mar 1, 2006
    #5
  6. Derek Basch

    James Stroud Guest

    Derek Basch wrote:
    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method
    > or should I pass around variable between the methods?
    >
    > Flamewar........NOW!
    >
    > jk, I really do want other opinions.
    >
    > Thanks,
    > Derek
    >


    I tend to think in terms of states. If a quantity/attribute is important
    for the state of an object, then it should be an instance variable. If
    it can be calculated from the state, then it can be made a read-only
    property, etc. If it is irrelevant to the state of an object, it
    probably should belong to another object or should be a global.

    Here is an example from chemistry:

    densities = {'H2O' : 1.0, 'Hg' : 13.6}

    class CupOfLiquid(object):
    def __init__(self, liquid, volume):
    self.liquid = liquid
    self.volume = volume
    def spill(self, spill_vol):
    newvol = self.volume - spill_vol
    if newvol < 0:
    raise SpillError, "Can't spill that much!"
    self.volume = newvol
    def get_mass(self):
    return densities[self.liquid] * self.volume
    mass = property(get_mass)

    Notice that it would be quite awkward to remember the volume state of a
    CupOfLiquid instance between method calls. One would need a global to do
    this, which defeats the purpose of using classes (i.e. object
    orientation). Notice also that the value of densities is independent of
    the state of any CupOfLiquid instance, so it is a global.

    As an exercise, try threading this object for evaporation. Hint, you
    might need a "lid_closed" attribute.

    James
    James Stroud, Mar 2, 2006
    #6
  7. Derek Basch

    Duncan Booth Guest

    Derek Basch wrote:

    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method
    > or should I pass around variable between the methods?


    Try to distinguish the state of the object from the parameters to methods.

    An object should always have a consistent state. Say you call a method, and
    that method calls a bunch of other methods. At almost any point during
    those method calls execution can leak out to other bits of code (e.g. you
    might think you are adding two values, but perhaps they have a user defined
    addition operator) and that other code might just call methods on the same
    object. This might not happen much in practice, but I think that if you
    imagine all method calls as potentially happening in parallel it avoids a
    lot of problems.

    So, for example, if you had a method which returned a formatted
    representation of something, and which took a precision as a parameter, you
    shouldn't be saving the precision in the object: it isn't part of the
    state, and if you save it as such one day you might find it changes under
    your feet mid call.

    A lot of objects benefit from being treated as immutable: i.e. initialise
    them on creation, but never modify the attributes after creation. This has
    the great benefit that you never need to worry about whether or not to copy
    an object: you always just keep using the same object until an attribute
    needs to change and then you just create a new one. Obviously this only
    works for lightweight objects, but that should be most of them.

    Passing one or two parameters around a host of methods is fine: if you are
    passing more then it probably indicates you need to invent another object
    to encapsulate the state associated with the method call. It is also likely
    that it means you then want to move some of the code logic into the new
    object. In other words, instead of:

    obj.meth1(a, b, c, d) calls obj.meth2(a, b, c, d) calls obj.meth3, ...

    (and perhaps meth2 only needs a, b and c so it can pass them on),
    you want some helper object constructed with a, b, c & d and parts of the
    original methods then get factored into methods on the help objects.
    Duncan Booth, Mar 2, 2006
    #7
  8. Derek Basch wrote:
    > This one has always bugged me. Is it better to just slap a "self" in
    > front of any variable that will be used by more than one class method


    s/class method/method/

    In Python, a "class method" is a method working on the class itself (not
    on a given instance).

    > or should I pass around variable between the methods?


    One of the first rules I learned (from experience...) was to restrict as
    much as possible the scope of a variable. It usually makes code more
    readable, more robust, and more modular. In fact, I sometime even pass
    attributes of an object as args to a method of the same object, and/or
    assign values returned from a method of an object to attributes of the
    same object. This is more explicit than relying on side-effects.

    So (as pointed by almost everyone in this thread...) the best criteria
    here is : is this variable part of the state of an object, or is it just
    a value used for a given computation ?

    Note that if you find yourself passing the same huge set of variables
    from method to method for a given computation, this may calls for a
    refactoring... Python objects can be callable (ie function-like), so a
    complex computation with lot of shared state (independant from the rest
    of the object) may be best implemented as a separate temporary callable
    object - which can take the calling object as a parameter if it needs to
    access other attributes from it.

    My 2 cents...
    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
    bruno at modulix, Mar 2, 2006
    #8
  9. Derek Basch

    Derek Basch Guest

    Wow! Thanks everyone. Such coherent and philisophical answers. I will
    read them all over on a lazy sunday as this type ethereal stuff hurts
    my head after about 30 seconds. All the gurus on the python list are so
    friggin' smart. This should improve my coding after I digest it all.
    Thanks Again!

    Derek Basch
    Derek Basch, Mar 13, 2006
    #9
  10. Derek Basch

    Derek Basch Guest

    So, if I am understanding what everyone is saying here. I should do my
    best to distinguish between values that are part of the "state" of an
    object and values that are more disposable and can change for each
    computation of a value. So if I create an instance of a "wallet" class
    and the color of the wallet is "red". The "red" value would be ideal as
    a class variable as it is tied to the state of that wallet instance.
    However, if the wallet class contains a function to compute the tax on
    a purchased item, the purchase price would be a good example of a
    passed parameter value. Am I on the right track?

    Thanks,
    Derek Basch
    Derek Basch, Mar 15, 2006
    #10
  11. Derek Basch

    Derek Basch Guest

    One more question everybody. Say you have a class that performs a
    series of evaluations on several strings of peptides. Let's say for the
    sake of argument:

    DMCDIYLLY
    FQPQNGQFI
    RHPENPNLL

    Heres the class:

    class PeptideEvaluator:

    def evaluate(self, peptide):
    peptide_name = peptide + "Rules!"
    result1 = self.test1(peptide, peptide_name)
    result2 = self.test2(peptide, peptide_name)
    result3 = self.test3(peptide, peptide_name)

    def test1(self, peptide, peptide_name):
    f = open(peptide_name + ".txt", "w")
    f.write(peptide)
    f.close()

    def test2(self, peptide, peptide_name):
    f = open(peptide_name + ".txt", "w")
    f.write(peptide)
    f.close()

    def test3(self, peptide, peptide_name):
    f = open(peptide_name + ".txt", "w")
    f.write(peptide)
    f.close()

    So, you instantiate a class called "PeptideEvaluator" and pass in each
    string to its "evaluate" method. Now you have to repeatedly pass the
    peptide and peptide_name to each function. According to what everyone
    has said declaring them as class variables is bad because they are not
    related to the state of the "PeptideEvaluator". How can I avoid having
    to pass the same parameters all over a class? I can';t quite seem to
    wrap my head around this one.

    Thanks again everyone,
    Derek Basch
    Derek Basch, Mar 15, 2006
    #11
  12. Derek Basch

    Terry Reedy Guest

    "Derek Basch" <> wrote in message
    news:...
    > So, if I am understanding what everyone is saying here. I should do my
    > best to distinguish between values that are part of the "state" of an
    > object and values that are more disposable and can change for each
    > computation of a value. So if I create an instance of a "wallet" class
    > and the color of the wallet is "red". The "red" value would be ideal as
    > a class variable as it is tied to the state of that wallet instance.
    > However, if the wallet class contains a function to compute the tax on
    > a purchased item, the purchase price would be a good example of a
    > passed parameter value. Am I on the right track?


    yes
    Terry Reedy, Mar 16, 2006
    #12
  13. Derek Basch

    Eric Brunel Guest

    On 15 Mar 2006 15:04:19 -0800, Derek Basch <> wrote:

    > One more question everybody. Say you have a class that performs a
    > series of evaluations on several strings of peptides.


    Errr..., no? A class does not perform some operations. A class is a
    template for objects. What are your objects? If you had a class Peptide
    for example (I'm guessing here; I'm not exactly fluent in this domain), I
    would have understood. But what you're describing here is not a class;
    it's just a set of functions.

    > Heres the class:
    >
    > class PeptideEvaluator:
    >
    > def evaluate(self, peptide):
    > peptide_name = peptide + "Rules!"
    > result1 = self.test1(peptide, peptide_name)
    > result2 = self.test2(peptide, peptide_name)
    > result3 = self.test3(peptide, peptide_name)
    >
    > def test1(self, peptide, peptide_name):
    > f = open(peptide_name + ".txt", "w")
    > f.write(peptide)
    > f.close()
    >
    > def test2(self, peptide, peptide_name):
    > f = open(peptide_name + ".txt", "w")
    > f.write(peptide)
    > f.close()
    >
    > def test3(self, peptide, peptide_name):
    > f = open(peptide_name + ".txt", "w")
    > f.write(peptide)
    > f.close()
    >
    > So, you instantiate a class called "PeptideEvaluator" and pass in each
    > string to its "evaluate" method. Now you have to repeatedly pass the
    > peptide and peptide_name to each function. According to what everyone
    > has said declaring them as class variables is bad because they are not
    > related to the state of the "PeptideEvaluator". How can I avoid having
    > to pass the same parameters all over a class? I can';t quite seem to
    > wrap my head around this one.


    QED: this "class" has no need at all for attributes, and does not even
    have a constructor. This is usually a strong signal that what you're doing
    is wrong. Just turn this class into a module containing functions. Or put
    these methods into another class (the Peptide class may be a good
    candidate if you have one; "evaluating" a peptide seems to be an operation
    that you do on peptides).

    HTH
    --
    python -c "print ''.join([chr(154 - ord(c)) for c in
    'U(17zX(%,5.zmz5(17;8(%,5.Z65\'*9--56l7+-'])"
    Eric Brunel, Mar 16, 2006
    #13
  14. Derek Basch

    Steve Holden Guest

    Derek Basch wrote:
    > So, if I am understanding what everyone is saying here. I should do my
    > best to distinguish between values that are part of the "state" of an
    > object and values that are more disposable and can change for each
    > computation of a value. So if I create an instance of a "wallet" class
    > and the color of the wallet is "red". The "red" value would be ideal as
    > a class variable as it is tied to the state of that wallet instance.


    Nope. Technically that would be an *instance* variable - each wallet
    instance can have a different colour. [This may be what you mean in
    whcih case please regard this as correcting your language, not your
    thinking. Class variables are available, and are normally single values
    share among all instances of a class.].

    > However, if the wallet class contains a function to compute the tax on
    > a purchased item, the purchase price would be a good example of a
    > passed parameter value. Am I on the right track?
    >

    Yes, that would be correct.

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd www.holdenweb.com
    Love me, love my blog holdenweb.blogspot.com
    Steve Holden, Mar 16, 2006
    #14
  15. On 15 Mar 2006 15:04:19 -0800
    "Derek Basch" <> wrote:
    >
    > class PeptideEvaluator:
    >
    > def evaluate(self, peptide):
    > [...]
    >
    > So, you instantiate a class called "PeptideEvaluator" and
    > pass in each string to its "evaluate" method. Now you have
    > to repeatedly pass the peptide and peptide_name to each
    > function. According to what everyone has said declaring
    > them as class variables is bad because they are not
    > related to the state of the "PeptideEvaluator". How can I
    > avoid having to pass the same parameters all over a class?
    > I can';t quite seem to wrap my head around this one.


    "PeptideEvaluator" suggests it's meant to act on some
    "data" object and produce a "result" object (you're
    reinventing functions, using object-oriented machinery?).

    A more usual OOP approach is to make an object "Peptide"
    which models the peptide, then put the methods on it.
    When you instantiate "Peptide" you tell it what its sequence
    is, and the methods provide your analysis -- you ask the
    object itself to give you the results. Then, of course,
    the peptide sequence *IS* a fundamental property of the
    object.

    If you have to separate this functionality into a separate
    object, you should immediately be asking yourself "why"? Is
    there a compelling reason you need *two* objects that have
    to communicate over an interface when one will do?
    (Sometimes there are).

    --
    Terry Hancock ()
    Anansi Spaceworks http://www.AnansiSpaceworks.com
    Terry Hancock, Mar 16, 2006
    #15
    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. E11
    Replies:
    1
    Views:
    4,710
    Thomas Weidenfeller
    Oct 12, 2005
  2. Adel
    Replies:
    3
    Views:
    305
    Jack Klein
    Mar 17, 2005
  3. Jason
    Replies:
    2
    Views:
    491
    Jonathan Mcdougall
    May 13, 2006
  4. Peter Loftus
    Replies:
    2
    Views:
    114
    cruiserdan
    Dec 18, 2007
  5. Dave Howell
    Replies:
    4
    Views:
    119
    Joel VanderWerf
    Jun 22, 2010
Loading...

Share This Page