Yes, of course (a silly cut-o / paste-o).
The problem with this is:
class A(object):
def __init__(self, *args, **kwargs):
print 'Set A(*%r, **%r)' % (args, kwargs)
class B(A):
def __init__(self, *args, **kwargs):
print 'Set B(*%r, **%r)' % (args, kwargs)
super(B, self).__init__(*args, **kwargs)
class C(B):
def __init__(self, *args, **kwargs):
print 'Set C(*%r, **%r)' % (args, kwargs)
super(C, self).__init__(*args, **kwargs)
class D(A):
def __init__(self, *args, **kwargs):
print 'Set D(*%r, **%r)' % (args, kwargs)
super(type(self), self).__init__(*args, **kwargs)
class E(D):
def __init__(self, *args, **kwargs):
print 'Set E(*%r, **%r)' % (args, kwargs)
super(type(self), self).__init__(*args, **kwargs)
You'll see the problem when you attempt to create an instance of E.
All of the others work just fine.
Ok, I had a brain-o ;-) If we had class decorators analogous to function decorators,
we could write
@deco(args)
class X: ...
instead of
class X: ...
X = deco(args)(X)
below, but anyway (untested beond what you see), using your example, have a look:
----< super_cls_deco.py >-------------------------------------------------------
# super_cls_deco.py -- bokr 2005-07-03
from ut.presets import presets # function local presets decorator
def preset_super_ubm(target_method_name, super_method_name, alias=None):
"""
class decorator to preset an unbound super-method as a local
alias name in a target method of the decorated class.
"""
if alias is None: alias = 'SUPER'+super_method_name # for local name in target method
def super_deco(cls):
if not getattr(cls, target_method_name):
raise ValueError, 'class %s does not have a %s method' %(
cls.__name__, target_method_name)
for base in cls.mro()[1:]:
if hasattr(base, super_method_name):
ubm = getattr(base, super_method_name)
setattr(cls, target_method_name, presets(**{alias:ubm})(
cls.__dict__[target_method_name]))
return cls
raise ValueError, '%s not found as super-method' % super_method_name
return super_deco
def test():
class A(object):
def __init__(self, *args, **kwargs):
print 'Set A(*%r, **%r)' % (args, kwargs)
SUPER__init__(self, *(('from A:',)+args), **kwargs)
A = preset_super_ubm('__init__', '__init__')(A)
class B(A):
def __init__(self, *args, **kwargs):
print 'Set B(*%r, **%r)' % (args, kwargs)
SUPER__init__(self, *(('from B:',)+args), **kwargs)
#super(B, self).__init__(*args, **kwargs)
B = preset_super_ubm('__init__', '__init__')(B)
class C(B):
def __init__(self, *args, **kwargs):
print 'Set C(*%r, **%r)' % (args, kwargs)
SUPER__init__(self, *(('from C:',)+args), **kwargs)
#super(C, self).__init__(*args, **kwargs)
C = preset_super_ubm('__init__', '__init__')(C)
class D(A):
def __init__(self, *args, **kwargs):
print 'Set D(*%r, **%r)' % (args, kwargs)
SUPER__init__(self, *(('from D:',)+args), **kwargs)
#super(type(self), self).__init__(*args, **kwargs)
D = preset_super_ubm('__init__', '__init__')(D)
class E(D):
def __init__(self, *args, **kwargs):
print 'Set E(*%r, **%r)' % (args, kwargs)
SUPER__init__(self, *(('from E:',)+args), **kwargs)
#super(type(self), self).__init__(*args, **kwargs)
E = preset_super_ubm('__init__', '__init__')(E)
print '... from creating instance %s\n' % A('some', 'args', a='keyword')
print '... from creating instance %s\n' % B('some', 'args', a='keyword')
print '... from creating instance %s\n' % C('some', 'args', a='keyword')
print '... from creating instance %s\n' % D('some', 'args', a='keyword')
print '... from creating instance %s\n' % E('some', 'args', a='keyword')
if __name__ == '__main__':
test()
--------------------------------------------------------------------------------
which results in:
[11:45] C:\pywk\clp>py24 super_cls_deco.py
Set A(*('some', 'args'), **{'a': 'keyword'})
.... from creating instance <__main__.A object at 0x02F031EC>
Set B(*('some', 'args'), **{'a': 'keyword'})
Set A(*('from B:', 'some', 'args'), **{'a': 'keyword'})
.... from creating instance <__main__.B object at 0x02F031EC>
Set C(*('some', 'args'), **{'a': 'keyword'})
Set B(*('from C:', 'some', 'args'), **{'a': 'keyword'})
Set A(*('from B:', 'from C:', 'some', 'args'), **{'a': 'keyword'})
.... from creating instance <__main__.C object at 0x02F031EC>
Set D(*('some', 'args'), **{'a': 'keyword'})
Set A(*('from D:', 'some', 'args'), **{'a': 'keyword'})
.... from creating instance <__main__.D object at 0x02F031EC>
Set E(*('some', 'args'), **{'a': 'keyword'})
Set D(*('from E:', 'some', 'args'), **{'a': 'keyword'})
Set A(*('from D:', 'from E:', 'some', 'args'), **{'a': 'keyword'})
.... from creating instance <__main__.E object at 0x02F031EC>
(presets is my function byte-code-hacking decorator that presets local names
in a function at decoration-time without using the default-argument hack)
E.g.,
Traceback (most recent call last):
File "<stdin>", line 1, in ?
1 0 LOAD_GLOBAL 0 (msg)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE 1 0 LOAD_CONST 1 ('this is a preset')
3 STORE_FAST 0 (msg)
3 6 LOAD_FAST 0 (msg)
9 PRINT_ITEM
10 PRINT_NEWLINE
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
A class decorator would avoid that nasty global name reference that bothers me ;-)
Regards,
Bengt Richter