Question about accessing class-attributes.

Alex Martelli aleax at aleax.it
Thu Apr 24 09:24:52 EDT 2003


Duncan Booth wrote:

> Nikolai Kirsebom <nikolai.kirsebom.NOJUNK at siemens.no> wrote in
> news:0kifav8dfcbu0t8j4qrrkq6ag7gcg1s062 at 4ax.com:
> 
>> class A(object):
>>      InstCount = 0
>>      def __init__(self):
>>           self.__class__.__dict__['InstCount'] += 1
>> 
>> class B(A):
>>      InstCount = 0
>> 
>> class C(A):
>>      InstCount = 0
>> 
>> Is the syntax used for incrementing the class-attribute for every
>> instanciation 'the way' it should be done ?
> 
> It would be more normal just to write:
> 
> self.__class__.InstCount += 1

Yes, but do note that this may produce strange anomalies if some
subclass erroneously forgets to rebind InstCount in its body...:

>>> class A(object):
...   InstCount = 0
...   def __init__(self):
...     self.__class__.InstCount += 1
...
>>> class B(A): pass
...
>>> a1=A()
>>> a2=A()
>>> b1=B()
>>> b2=B()
>>> B.InstCount
4
>>> A.InstCount
2
>>>

VERY unlikely to be what one wants, AND a rather subtle bug too.
The OP's direct access to __class__.__dict__ would ensure an
exception got raised upon instantiation of such an errant subclass.


> Alternatively you could create a class method to do the increment, but
> that is probably needlessly complex here.

Personally, I'd define a custom metaclass for this purpose.  Maybe
I'm getting TOO familiar with those, but, it doesn't sound all that
complex at all to me...:

>>> class metaIC(type):
...     def __new__(cls, name, bases, dict):
...         dict['InstCount'] = 0
...         return type.__new__(cls, name, bases, dict)
...     def __call__(cls, *args, **kwds):
...         cls.InstCount += 1
...         return type.__call__(cls, *args, **kwds)
...
>>> class A(object):
...   __metaclass__ = metaIC
...
>>> class B(A): pass
...
>>> a1=A(); a2=A(); a3=A()
>>> b1=B()
>>> A.InstCount
3
>>> B.InstCount
1
>>>

...isn't this smoother and handier?  Or does it just look that way
to me, due to overexposure to custom metaclasses?-)

When I think of behavior to be associated with a CLASS rather than
its INSTANCES, such as this case, more and more my thoughts turn to
a custom metaclass to encapsulate that behavior.  And why not?  it
does seem to be the normal way of OO -- just as I'd think of the
class in order to define behavior for its instances...


Alex





More information about the Python-list mailing list