Question about accessing class-attributes.

Bjorn Pettersen BPettersen at NAREX.com
Thu Apr 24 11:35:26 EDT 2003


> From: Alex Martelli [mailto:aleax at aleax.it] 
> 
> 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...:
[...]

I would too, but just for fun I thought "how about an abstract base
class?". Due to a 'thinko' I didn't consider that B wasn't calling its
superclass __init__, so I came up with:

  class AbstractBaseCounter(object):
      __InstCount = {}
      def InstCount(cls):
          return AbstractBaseCounter.__InstCount[cls]
      InstCount = classmethod(InstCount)
      
      def __init__(self):
          cls = self.__class__
          if cls == AbstractBaseCounter:
              raise TypeError("Attempt to instantiate abstract base
class")
          d = AbstractBaseCounter.__InstCount
          if cls in d:
              d[cls] += 1
          else:
              d[cls] = 1
          
  class A(AbstractBaseCounter):
      def __init__(self):
          AbstractBaseCounter.__init__(self)
          
  class B(A): pass
          
  a1=A()
  a2=A()
  b1=B()
  b2=B()
  print B.InstCount()

which happens to work...? I've verified that
AbstractBaseCounter.__init__ gets called for B(). Is this
correct/documented/guaranteed/works with MI/multiple args/old-style
classes, etc., etc.?

Of course, if you wanted to make InstCount a class atribute (so you
could say B.InstCount without the parentesis), you'd need a metaclass.

Python 2.3a2.

-- bjorn





More information about the Python-list mailing list