Style question - defining immutable class data members

Gary Herron gherron at islandtraining.com
Sat Mar 14 16:31:29 EDT 2009


Maxim Khitrov wrote:
> On Sat, Mar 14, 2009 at 2:07 PM, Gary Herron <gherron at islandtraining.com> wrote:
>   
>> Maxim Khitrov wrote:
>>     
>>> Very simple question on the preferred coding style. I frequently write
>>> classes that have some data members initialized to immutable values.
>>> For example:
>>>
>>> class Test(object):
>>>    def __init__(self):
>>>        self.some_value = 0
>>>        self.another_value = None
>>>
>>> Similar effect can be achieved by defining some_value and
>>> another_value for the entire class, like so:
>>>
>>> class Test(object):
>>>    some_value = 0
>>>    another_value = None
>>>
>>> The advantage of doing this is that the assignments are evaluated once
>>> and thus the creation of that class is a bit faster. Access is still
>>> performed through self.some_value and self.another_value. Is there a
>>> reason to prefer the first style over the second?
>>>
>>> - Max
>>> --
>>> http://mail.python.org/mailman/listinfo/python-list
>>>
>>>       
>> Such things are often called class attributes, and the are fine.  If you
>> look through Python's standard library,  you will find many examples of
>> class attributes.
>>
>> However, you appear to have either a misuse or misconception of the word
>> "immutable' here.   Whether the value you assign to a class attribute is
>> mutable or immutable is irrelevant.   Also whether you plan on leaving the
>> value constant or not is also not relevant.
>> What does matter is this:  If every instance wants access to a single value
>> (immutable or not), use a class attribute, otherwise use an instance
>> attribute.
>>
>> Gary Herron
>>     
>
> Perhaps a different example would help explain what I'm trying to do:
>
> class Case1(object):
> 	def __init__(self):
> 		self.count = 0
> 		self.list  = []
>
> 	def inc(self):
> 		self.count += 1
> 		self.list.append(self.count)
>
> 	def val(self):
> 		return (self.count, self.list)
>
> class Case2(object):
> 	count = 0
> 	list  = []
>
> 	def inc(self):
> 		self.count += 1
> 		self.list.append(self.count)
>
> 	def val(self):
> 		return (self.count, self.list)
>
> for i in xrange(10):
> 	c1 = Case1()
> 	c2 = Case2()
>
> 	for j in xrange(i):
> 		c1.inc()
> 		c2.inc()
>
> 	v1, l1 = c1.val()
> 	v2, l2 = c2.val()
>
> 	print v1 == v2, l1 == l2
>
> The only difference between Case1 and Case2 classes is where the count
> and list attributes are defined. You will notice that for an immutable
> type (count), this doesn't matter. On the last line, v1 == v2 is
> always True. When the type is mutable (list), you must define it in
> __init__. This isn't about class attributes or shared instance
> attributes/constants. This is about a small optimization in defining
> per-instance variables. This optimization only applies to immutable
> types.
>
> - Max
> --
> http://mail.python.org/mailman/listinfo/python-list
>   

But now you are not listening to what people are telling you.  It has 
*nothing* to do with the mutability/immutability of the integer and the 
list your two classes create.

The difference is this:

    For C1:  You create 10 instances of C1.  Each one creates its own  
count, and a list variables, and manipulates them calls to inc and val.  
Then each on is discarded as you go through the next pass on the outer loop.

    For C2;  You create 10 instances of C2, but these 10 instances each 
manipulate values created once in the class itself.  The values 
manipulated by one instance of C2 in one pass through the loop are not 
affected when, on the next pass through the loop, that instance is 
destroyed and another instance is created. 

So...

  If you want a variable that records/supplies some value across *all* 
instances of a class, use a class variable. 
  (Or use a global variable -- it would have the same effect.)

  If you want a variable whose value is unique to each instance of a 
class, then make it an instance variable.

Gary Herron




More information about the Python-list mailing list