Inheriting from object
Bengt Richter
bokr at oz.net
Sun Jul 3 14:53:28 EDT 2005
On Sat, 02 Jul 2005 12:26:49 -0700, Scott David Daniels <Scott.Daniels at Acm.Org> wrote:
>Bengt Richter wrote:
>> On Thu, 30 Jun 2005 08:54:31 -0700, Scott David Daniels <Scott.Daniels at Acm.Org> wrote:
>>>Or, perhaps:
>>> class foo(object):
>>> def __init__(self, *args, **kwargs):
>>> super(foo, self).__init__(self, *args, **kwargs)
>>> ...
>>>
>>
>> Doesn't super(foo, self).__init__ return a bound method, so you don't
>> need to pass self again? I.e.,
>> super(foo, self).__init__(*args, **kwargs)
>
>Yes, of course (a silly cut-o / paste-o).
>
>> BTW, there's something about referring to type(self) by its not
>> always dependably bound (though usually global) name that bothers me.
>>
>> I wonder if the above common use of super could be implemented as a property of object,
>> so you'd normally inherit it and be able to write
>> self.super.__init__(*args, **kwargs) # (maybe spell it self.__super__.__init__(...) I suppose)
>>
>> I.e., self.__super__ would effectively return the equivalent of
>> super(type(self), self)
>
>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.,
>>> from ut.presets import presets
>>> def foo(): print msg
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in foo
NameError: global name 'msg' is not defined
>>> import dis
>>> dis.dis(foo)
1 0 LOAD_GLOBAL 0 (msg)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
>>> foo = presets(msg='this is a preset')(foo) # manual decoration call
>>> foo()
this is a preset
>>> dis.dis(foo)
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
More information about the Python-list
mailing list