Inheriting from object

F

Fuzzyman

Hello,

To create a classic (old style) class, I write :

class foo:
pass

To do the equivalent as a new style class, I write :

class foo(object):
pass

*Should* I in fact write :

class foo(object):
def __init__(self, *args, **kwargs):
object.__init__(self)

?

Also, can anyone explain any tangible benefit of inheriting from
object, when not explicitly using any features of new style classes ?

Thanks :)

Fuzzyman
http://www.voidspace.org.uk/python
 
R

Robert Kern

Fuzzyman said:
Hello,

To create a classic (old style) class, I write :

class foo:
pass

To do the equivalent as a new style class, I write :

class foo(object):
pass

*Should* I in fact write :

class foo(object):
def __init__(self, *args, **kwargs):
object.__init__(self)

?

I don't believe so.
Also, can anyone explain any tangible benefit of inheriting from
object, when not explicitly using any features of new style classes ?

This class might not, but you (or someone else) may decide later to
subclass it and want to use those features. It's a good habit to get
into even if you don't initially plan on using those features.

--
Robert Kern
(e-mail address removed)

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
 
B

Bruno Desthuilliers

Fuzzyman a écrit :
Hello,

To create a classic (old style) class, I write :

class foo:
pass

To do the equivalent as a new style class, I write :

class foo(object):
pass

*Should* I in fact write :

class foo(object):
def __init__(self, *args, **kwargs):
object.__init__(self)

?
Nope.

Also, can anyone explain any tangible benefit of inheriting from
object, when not explicitly using any features of new style classes ?

old-style classes are deprecated. They are still in the language (for
how much time ?) for compatibility reasons, but they won't last forever.
That should be a good enough reason to avoid them, given that the
only thing you have to do is to inherit from object...
 
B

Benji York

Fuzzyman said:
Also, can anyone explain any tangible benefit of inheriting from
object, when not explicitly using any features of new style classes ?

One reason is that properties won't work correctly.
 
F

Fuzzyman

So theres no actual advantage that you know of ;-)

Surely when they are removed :

class foo:
pass

won't become invalid syntax, it will just automatically inherit from
object ?

That's what I assumed, anyway....

Regards,

Fuzz
http://www.voidspace.org.uk/python
 
S

Steven Bethard

Fuzzyman said:
Surely when they are removed :

class foo:
pass

won't become invalid syntax, it will just automatically inherit from
object ?

Well, Guido views this particular syntax as an "oopsie"[1]. It should
actually look like:

class C():
pass

Guido also suggests that the explicit:

class C(object):
pass

is "much preferred"[2] over:

__metaclass__ = type

class C:
pass

when creating new-style classes. It's not exactly clear where Guido
comes down on your particular issue, but if I had to guess, I would
guess that he prefers the explicit reference to "object".

STeVe

[1]http://mail.python.org/pipermail/python-dev/2005-February/051706.html
[2]http://mail.python.org/pipermail/python-dev/2005-February/051711.html
 
D

Dave Benjamin

Steven said:
Guido also suggests that the explicit:

class C(object):
pass

is "much preferred"[2] over:

__metaclass__ = type

class C:
pass

Really? I have been toying with the idea of using the __metaclass__
trick, since it results in completely valid Jython 2.1 code, as long as
you don't use any of the new-style features.

But once Brian Zimmer gets his broadband fixed, we're supposed to get a
new alpha release. =)

Dave
 
F

Fuzzyman

The reason I ask is that I often (well... a couple of times anyway) see
cryptic omments like :

and if you inherit from object you get all the benefits of new
style classes

Now I know about the advantages of inheriting from the built in types
(if that's what you want to do) -but am a bit fuzzier on the 'general
benefits'.

I'm vaguely aware of properties.... I'll have to explore them at some
point.

Best Regards,

Fuzzy
http://www.voidspace.org.uk/python
 
S

Sion Arrowsmith

Bruno Desthuilliers said:
Fuzzyman a écrit :
Nope.

And if you were to do so, surely:

class foo(object):
def __init__(self, *args, **kwargs):
super(foo, self).__init__(self)

would be the preferred way to go?
 
S

Scott David Daniels

Sion said:
... And if you were to do so, surely:
class foo(object):
def __init__(self, *args, **kwargs):
super(foo, self).__init__(self)

would be the preferred way to go?
Or, perhaps:
class foo(object):
def __init__(self, *args, **kwargs):
super(foo, self).__init__(self, *args, **kwargs)
...

--Scott David Daniels
(e-mail address removed)
 
B

Bengt Richter

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)

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)

(I think Michele Simionato may have posted some idea like this early on that
I didn't really follow, but maybe my subconscious snagged and garbled ;-)

Regards,
Bengt Richter
 
P

Peter Hansen

Bengt said:
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)

This doesn't work: type(self) is always the type of the instantiated
(child) class, not the type of the class at whatever level of the class
hierarchy the __init__() calls currently have reached.

In other words, with these definitions:

class A(object):
def __init__(self):
super(type(self), self).__init__() # does not do what you want

class B(A):
def __init__(self):
super(type(self), self).__init__() # works okay here

if you do "b = B()", the first __init__ will work (i.e. B's __init__
will find and call A.__init__), but the next one won't (i.e. A.__init__
will now try calling A.__init__ recursively, giving you an eventual
stack overflow).

-correcting-bengt-richter-on-such-arcana-is-always-dangerously y'rs,
Peter
 
S

Scott David Daniels

Bengt said:
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.

--Scott David Daniels
(e-mail address removed)
 
S

Steven Bethard

Bengt said:
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)

(I think Michele Simionato may have posted some idea like this early on that
I didn't really follow, but maybe my subconscious snagged and garbled ;-)

Here's the link I believe you're referring to:
http://groups-beta.google.com/group/comp.lang.python/msg/0034684c138cf9f3

Probably worth reading for anyone interested in making super syntax
"look prettier". Basically Michele shows that the current super()
object fails in a number of ways when you try to make it a class attribute.

STeVe
 
J

John Roth

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)

Well, let's look at it. If I implemented a super() method on
object (and I didn't shadow it anywhere) what I'd have when
it was invoked is something like

def super(self):
stuff

From there one could get the current instance's class, so
we've got all the ingredients of the regular super(class, instance)
built-in function. What it wouldn't have is the ability to invoke it
on an arbitrary class and instance.

The big issue seems to be the direction Guido wants to take
Python - he seems to not want to put methods on the
object type. I have to say that I don't understand his reasoning,
if that is indeed his position.

John Roth
 
B

Bengt Richter

This doesn't work: type(self) is always the type of the instantiated
(child) class, not the type of the class at whatever level of the class
hierarchy the __init__() calls currently have reached.
D'oh, you're right, that was too easy a property definition ;-/
I still don't like having to use a global name to get access to the
current lexical scope object though. But I can't think of a decent hack
right now to get around all that, and I can't spend too much time ;-/
In other words, with these definitions:

class A(object):
def __init__(self):
super(type(self), self).__init__() # does not do what you want

class B(A):
def __init__(self):
super(type(self), self).__init__() # works okay here

if you do "b = B()", the first __init__ will work (i.e. B's __init__
will find and call A.__init__), but the next one won't (i.e. A.__init__
will now try calling A.__init__ recursively, giving you an eventual
stack overflow).

-correcting-bengt-richter-on-such-arcana-is-always-dangerously y'rs,
Peter
No danger at all, I'm grateful ;-)

Regards,
Bengt Richter
 
B

Bengt Richter

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top