Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #45331 > unrolled thread

Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs

Started bywzab <wzab01@gmail.com>
First post2013-05-15 04:18 -0700
Last post2013-05-15 09:41 -0600
Articles 6 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs wzab <wzab01@gmail.com> - 2013-05-15 04:18 -0700
    Re: Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-15 13:16 +0100
      Re: Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-16 02:06 +0000
        Re: Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-16 00:37 -0600
        Re: Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-16 11:31 +0100
    Re: Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-15 09:41 -0600

#45331 — Python 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs

Fromwzab <wzab01@gmail.com>
Date2013-05-15 04:18 -0700
SubjectPython 2.7.x - problem with obejct.__init__() not accepting *args and **kwargs
Message-ID<f4ce525a-2728-4ad6-9858-e9005534ee54@bz1g2000vbb.googlegroups.com>
I had to implement in Python 2.7.x a system which heavily relies on
multiple inheritance.
Working on that, I have came to very simplistic code which isolates
the problem:
(The essential thing is that each base class receives all arguments
and uses only those,
which it understands).

class a(object):
  def __init__(self,*args,**kwargs):
    super(a,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in a"

class b(object):
  def __init__(self,*args,**kwargs):
    super(b,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in b"

class c(a,b):
  def __init__(self,*args,**kwargs):
    super(c,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in c"

z=c(test=23,data="eee")

In Python 2.5.2 the above code works correctly, and produces:

$python test1.py
()
{'test': 23, 'data': 'eee'}
init in b
()
{'test': 23, 'data': 'eee'}
init in a
()
{'test': 23, 'data': 'eee'}
init in c

Unfortunately in Python 2.7 the above code generates an exception:
$ python test1.py
Traceback (most recent call last):
  File "test1.py", line 22, in <module>
    z=c(test=23,data="eee")
  File "test1.py", line 17, in __init__
    super(c,self).__init__(*args,**kwargs)
  File "test1.py", line 3, in __init__
    super(a,self).__init__(*args,**kwargs)
  File "test1.py", line 10, in __init__
    super(b,self).__init__(*args,**kwargs)
TypeError: object.__init__() takes no parameters

I have found a workaround:

# Class my_object added only as workaround for a problem with
# object.__init__() not accepting any arguments.

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

class a(my_object):
  def __init__(self,*args,**kwargs):
    super(a,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in a"

class b(my_object):
  def __init__(self,*args,**kwargs):
    super(b,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in b"

class c(a,b):
  def __init__(self,*args,**kwargs):
    super(c,self).__init__(*args,**kwargs)
    print args
    print kwargs
    print "init in c"

z=c(test=23,data="eee")

The above works correctly, producing the same results as the first
code in Python 2.5.2,
but anyway it seems to me just a dirty trick...
What is the proper way to solve that problem in Python 2.7.3?

--
TIA,
Wojtek

[toc] | [next] | [standalone]


#45335

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-05-15 13:16 +0100
Message-ID<mailman.1695.1368620192.3114.python-list@python.org>
In reply to#45331
On 15 May 2013 12:18, wzab <wzab01@gmail.com> wrote:
> I had to implement in Python 2.7.x a system which heavily relies on
> multiple inheritance.
> Working on that, I have came to very simplistic code which isolates
> the problem:
> (The essential thing is that each base class receives all arguments
> and uses only those,
> which it understands).
>
[snip]
>
> I have found a workaround:
>
> # Class my_object added only as workaround for a problem with
> # object.__init__() not accepting any arguments.
[snip]
>
> The above works correctly, producing the same results as the first
> code in Python 2.5.2,
> but anyway it seems to me just a dirty trick...
> What is the proper way to solve that problem in Python 2.7.3?

I don't generally use super() but I did see some advice about it in
this article:
https://fuhm.net/super-harmful/

>From the conclusion:
"Never use positional arguments in __init__ or __new__. Always use
keyword args, and always call them as keywords, and always pass all
keywords on to super."


Oscar

[toc] | [prev] | [next] | [standalone]


#45389

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-16 02:06 +0000
Message-ID<51943f13$0$29997$c3e8da3$5496439d@news.astraweb.com>
In reply to#45335
On Wed, 15 May 2013 13:16:09 +0100, Oscar Benjamin wrote:


> I don't generally use super() 

Then you should, especially in Python 3.

If you're not using super in single-inheritance classes, then you're 
merely making your own code harder to read and write, and unnecessarily 
difficult for others to use with multiple-inheritance.

If you're not using super in multiple-inheritance[1] classes, then your 
code is probably buggy.

There really is no good reason to avoid super in Python 3.


> but I did see some advice about it in this article:
> https://fuhm.net/super-harmful/

It's not a good article. The article started off claiming that super was 
harmful, hence the URL. He's had to back-pedal, and *hard*. The problem 
isn't that super is harmful, it is that the problem being solved -- 
generalized multiple inheritance -- is inherently a fiendishly difficult 
problem to solve. Using super and cooperative multiple inheritance makes 
it a merely difficult but tractable problem.

The above article is useful to see the sorts of issues that can come up 
in multiple inheritance, and perhaps as an argument for avoiding MI 
(except in the tamed versions provided by mixins or straits). But as an 
argument against super? No.

A much better article about super is:

http://rhettinger.wordpress.com/2011/05/26/super-considered-super/


> From the conclusion:
> "Never use positional arguments in __init__ or __new__. Always use
> keyword args, and always call them as keywords, and always pass all
> keywords on to super."

Even that advice is wrong. See Super Considered Super above.




[1] To be precise: one can write mixin classes without super, and 
strictly speaking mixins are a form of multiple inheritance, but it is a 
simplified version of multiple inheritance that avoids most of the 
complications.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#45405

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-16 00:37 -0600
Message-ID<mailman.1737.1368686317.3114.python-list@python.org>
In reply to#45389
On Wed, May 15, 2013 at 8:06 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Wed, 15 May 2013 13:16:09 +0100, Oscar Benjamin wrote:
>
>
>> I don't generally use super()
>
> Then you should, especially in Python 3.
>
> If you're not using super in single-inheritance classes, then you're
> merely making your own code harder to read and write, and unnecessarily
> difficult for others to use with multiple-inheritance.
>
> If you're not using super in multiple-inheritance[1] classes, then your
> code is probably buggy.
>
> There really is no good reason to avoid super in Python 3.

The Python 3 syntactic sugar is the primary reason that I've finally
started using super in single-inheritance classes.  The magicalness of
it still disturbs me a bit, though.

>>> class A:
...     def __str__(self):
...         return super().__str__()
...
>>> class B:
...     __str__ = A.__str__
...
>>> A().__str__
<bound method A.__str__ of <__main__.A object at 0x0289E3B0>>
>>> str(A())
'<__main__.A object at 0x0289E270>'
>>> B().__str__
<bound method B.__str__ of <__main__.B object at 0x0289E470>>

The transplanted __str__ method is considered a method of B by Python...

>>> str(B())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __str__
TypeError: super(type, obj): obj must be an instance or subtype of type

But you can't use it because the super() call is irrevocably tied to
class A.  :-P

Of course the same is true with the syntax "super(A, self)", but at
least with that syntax it is clear that the method is explicitly
referencing class A, and so should not be expected to work correctly
in class B.  By contrast the syntax "super()" looks misleadingly
generic.

[toc] | [prev] | [next] | [standalone]


#45418

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-05-16 11:31 +0100
Message-ID<mailman.1748.1368700291.3114.python-list@python.org>
In reply to#45389
On 16 May 2013 03:06, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Wed, 15 May 2013 13:16:09 +0100, Oscar Benjamin wrote:
>
>
>> I don't generally use super()
>
> Then you should, especially in Python 3.
>
> If you're not using super in single-inheritance classes, then you're
> merely making your own code harder to read and write, and unnecessarily
> difficult for others to use with multiple-inheritance.
>
> If you're not using super in multiple-inheritance[1] classes, then your
> code is probably buggy.
>
> There really is no good reason to avoid super in Python 3.

I should have been clearer. I don't generally use super() because I
don't generally use Python in a very object-oriented way. My comment
was intended as a qualification of my advice rather than a suggestion
that there is something wrong with super(). I can certainly see how
that would be misinterpreted given the article I linked to:

>> but I did see some advice about it in this article:
>> https://fuhm.net/super-harmful/
>
> It's not a good article. The article started off claiming that super was
> harmful, hence the URL. He's had to back-pedal, and *hard*. The problem
> isn't that super is harmful, it is that the problem being solved --
> generalized multiple inheritance -- is inherently a fiendishly difficult
> problem to solve. Using super and cooperative multiple inheritance makes
> it a merely difficult but tractable problem.
>
> The above article is useful to see the sorts of issues that can come up
> in multiple inheritance, and perhaps as an argument for avoiding MI
> (except in the tamed versions provided by mixins or straits). But as an
> argument against super? No.

I read that article when I was trying to do something with multiple
inheritance. It was helpful to me at that time as it explained why
whatever I was trying to do (I don't remember) was never really going
to work.

>
> A much better article about super is:
>
> http://rhettinger.wordpress.com/2011/05/26/super-considered-super/

This is a good article and I read it after Ian posted it.

>
>
>> From the conclusion:
>> "Never use positional arguments in __init__ or __new__. Always use
>> keyword args, and always call them as keywords, and always pass all
>> keywords on to super."
>
> Even that advice is wrong. See Super Considered Super above.

Raymond's two suggestions for signature are:
'''
One approach is to stick with a fixed signature using positional
arguments. This works well with methods like __setitem__ which have a
fixed signature of two arguments, a key and a value. This technique is
shown in the LoggingDict example where __setitem__ has the same
signature in both LoggingDict and dict.

A more flexible approach is to have every method in the ancestor tree
cooperatively designed to accept keyword arguments and a
keyword-arguments dictionary, to remove any arguments that it needs,
and to forward the remaining arguments using **kwds, eventually
leaving the dictionary empty for the final call in the chain.
'''

The first cannot be used with object.__init__ and the second is not
what the OP wants. I think from the article that the appropriate
suggestion is to do precisely what the OP has done and make everything
a subclass of a root class that has the appropriate signature. Perhaps
instead of calling it my_object it could have a meaningful name
related to what the subclasses are actually for and then it wouldn't
seem so much like a dirty trick.

> [1] To be precise: one can write mixin classes without super, and
> strictly speaking mixins are a form of multiple inheritance, but it is a
> simplified version of multiple inheritance that avoids most of the
> complications.

They're also mostly the only kind of multiple inheritance that I would
think of using.


Oscar

[toc] | [prev] | [next] | [standalone]


#45354

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-15 09:41 -0600
Message-ID<mailman.1705.1368632544.3114.python-list@python.org>
In reply to#45331
On Wed, May 15, 2013 at 6:16 AM, Oscar Benjamin
<oscar.j.benjamin@gmail.com> wrote:
> I don't generally use super() but I did see some advice about it in
> this article:
> https://fuhm.net/super-harmful/
>
> From the conclusion:
> "Never use positional arguments in __init__ or __new__. Always use
> keyword args, and always call them as keywords, and always pass all
> keywords on to super."

While that article is a good read, this one is a bit better on giving
advice about how to practically use super:

http://rhettinger.wordpress.com/2011/05/26/super-considered-super/

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web