Question about accessing class-attributes.
Alex Martelli
aleax at aleax.it
Thu Apr 24 16:58:36 EDT 2003
Bjorn Pettersen wrote:
...
> Then define a hierarchy:
>
> class Counted(object):
> __metaclass__ = metaIC
>
> class Point(object):
> __metaclass__ = metaMetaBunch
> x = 0
> y = 0
>
> class CountedPoint(Counted, Point):
> def __init__(self):
> super(CountedPoint.self).__init__(self)
hmmm. I think you want a comma there, not a dot, in the super args.
And you shouldn't pass self as an argument here, either. Just:
super(CountedPoint, self).__init__()
But really, this whole __init__ method has no reason for being,
as it's just delegating to exactly the same method that would be
used if it didn't exist!!! So, snip it...
...
> not exactly clear _what_ the conflict is, i.e. it's not that the meta
> classes must have a common base (both isinstance(x, type), it's not that
> type.__new__ should perhaps be super(x, type).__new__, it _is_ that the
> metaclasses aren't related by inheritance. Trying to fix this by, e.g.
"Related by inheritance" may be a bit too weak. More specifically:
when class A(B, C, D): ... the constraint is that type(A) is a
subclass of each of type(B) and type(C). E.g., try this:
class meta1(type): pass
class C1: __metaclass__ = meta1
class meta2(type): pass
class C2: __metaclass__ = meta2
try:
print 'C1, C2',
class C3(C1, C2): pass
except TypeError:
print 'no'
else:
print 'yes'
class meta3(meta2, meta1): pass
class C3(C1, C2): __metaclass__ = meta3
print "with metaclass MI, though, it's fine!"
But in some cases, yes, weaker inheritance constraints between
meta-classes can suffice.
> making metaIC a subclass of metaMetaBunch (and changing the __new__ call
> appropriately), gives you:
>
> Traceback (most recent call last):
> File "M:\python\cpoint.py", line 38, in ?
> class CountedPoint(Counted, Point):
> File "M:\python\cpoint.py", line 25, in __new__
> return metaMetaBunch.__new__(cls, name, bases, dict)
> File "M:\python\cpoint.py", line 20, in __new__
> return type.__new__(cls, classname, bases, newdict)
> TypeError: multiple bases have instance lay-out conflict
>
> which means you're stuck (?)
Well no -- you MIGHT be stuck if you ever needed two different AND
incompatible __new__ in the same class, but here metaIC may just as
well use __init__ instead (as it ain't messing with e.g. __slots__:-)
so everything works if you recode the whole mess as, e.g.:
class metaMetaBunch(type):
def __new__(cls, classname, bases, classdict):
def __init__(self, **kw):
for k in self.__dflts__: setattr(self, k, self.__dflts__[k])
for k in kw: setattr(self, k, kw[k])
newdict = {'__slots__':[], '__dflts__':{}, '__init__':__init__}
for k in classdict:
if k.startswith('__'):
newdict[k] = classdict[k]
else:
newdict['__slots__'].append(k)
newdict['__dflts__'][k] = classdict[k]
return type.__new__(cls, classname, bases, newdict)
class metaIC(metaMetaBunch):
def __init__(cls, name, bases, dict):
cls.InstCount = 0
def __call__(cls, *args, **kwds):
cls.InstCount += 1
return type.__call__(cls, *args, **kwds)
class Counted(object):
__metaclass__ = metaIC
class Point(object):
__metaclass__ = metaMetaBunch
x = 0
y = 0
class CountedPoint(Counted, Point): pass
cp = CountedPoint()
print cp
But given the dependencies I don't think this particular mixin
mesh makes much sense. I'd rather merge two metaclasses into a
third one (solving any __new__-related conflicts of course;-)
rather than arbitrarily deriving one from the other (and it IS
arbitrary -- now you're forcing ANYTHING that's counted to be
SOME kind of metabunch...).
Alex
More information about the Python-list
mailing list