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