total idiot question: +=, .=, etc...
Tim Peters
tim_one at email.msn.com
Tue Jun 29 03:15:19 EDT 1999
>> class A(B):
>> def __init__(self, x, y, z):
>> B.__init__(self, x, y, z)
>>
>> can be grating too
[Greg Ewing]
> I could live with having to explicitly name the
> superclass, provided something checked that the
> class I named was actually a direct base class
> of the one where the method is defined. That
> way things would be less likely to break
> mysteriously when I rearrange the class
> hierarchy.
>
> I'm still thinking about how to implement
> this...
Hard! Class attrs (like __init__) don't point back to the class they belong
to. In the absence of sharing, though, the class chain can be searched for
the class that owns a particular attr value. I'll attach something that
does that; it's ugly; I'll never use it <wink>; could speed it a lot by
caching the search result.
seems-a-lot-easier-to-do-it-by-eye-ly y'rs - tim
class BaseInit:
"""A mixin class for "safe" superclass __init__ calls.
class X(Y, Z, ..., BaseInit):
def __init__(self, whatever):
self.baseinit(K, whatever)
self.baseinit(K, whatever) invokes K.__init__(self, whatever), but
raises an error unless K is a direct base class of X (the class
in which the __init__ calling baseinit is defined).
"""
def baseinit(self, base, *args, **kwargs):
import sys
if not isinstance(self, base):
raise TypeError(`self` + " isn't even an instance of " +
`base`)
# init <- code object of __init__ we were called from
try:
raise 'bogus'
except 'bogus':
tb = sys.exc_info()[2]
init = tb.tb_frame.f_back.f_code # back to the __init__
if init.co_name != "__init__":
raise ValueError("baseinit must be called from __init__")
# search the class hierarchy for that __init__, setting
# c to the class it belongs to
candidates = [self.__class__]
while candidates:
c = candidates.pop(0)
if c.__dict__.has_key("__init__"):
cinit = c.__init__.im_func.func_code
if init is cinit:
break
candidates = list(c.__bases__) + candidates
else:
raise SystemError("didn't find __init__ in class or bases!")
if base not in c.__bases__:
raise TypeError("attempt to init superclass " + `base` +
" from " + `c` + " but the "
"superclass isn't an immediate base class")
apply(base.__init__, (self,) + args, kwargs)
class A:
def __init__(self):
print "in A's init"
class B(A, BaseInit):
def __init__(self):
print "in B's init"
self.baseinit(A)
class C(B, BaseInit):
def __init__(self):
print "in C's init"
self.baseinit(B)
print "next one should be bogus"
self.baseinit(A)
b = B()
c = C()
More information about the Python-list
mailing list