3

Here is a minimal example:

This works in both python 3.5 and 2.7:

class A(object):
  def __init__(self, foo):
    self._foo = foo

class B(A):
  def __init__(self, foo):
    A.__init__(self, foo=foo)

b = B(1)

Change line:

    A.__init__(self, foo=foo)

to

    A.__init__(self=self, foo=foo)

In python 3.5 works without problems, but in python 2.7 you will receive the following error:

Traceback (most recent call last):
  File "self_key.py", line 9, in <module>
    b = B(1)
  File "self_key.py", line 7, in __init__
    A.__init__(self=self, foo=foo)
TypeError: unbound method __init__() must be called with A instance as first argument (got nothing instead)

Is self as keyword argument forbidden in python 2.7 or is this a bug?

Update

I'm aware that python will use the first parameter of a bound function to pass the reference to the object from which has been called. I also know that the __init__ function expects that this parameter is an instance of the class. In this case A.__init__ is unbound so we must provide that parameter manually.

When I asked about self as keyword argument forbidden I'm speaking about self as "the first parameter of __init__", which is supposed to receive a reference of the object to initialize. The name of the variable itself doesn't matter. We can perfectly change the name to this:, for example:

class A(object):
  def __init__(this, foo):
    this._foo = foo

class B(A):
  def __init__(self, foo):
    A.__init__(this=self, foo=foo)

b = B(1)

And it will be the same.

My question is why when calling the function we can perfectly specify that parameter as a positional argument (A.__init__(self, foo=foo)) but when we try to pass it as a keyword argument (A.__init__(this=self, foo=foo)) python 2.7 throws an error.

jabozzo
  • 591
  • 1
  • 6
  • 17

2 Answers2

0

Always use self for the first argument to instance methods.

Source: Python Documentation

NSNoob
  • 5,548
  • 6
  • 41
  • 54
Mark Simpson
  • 2,344
  • 2
  • 23
  • 31
  • By reading this I've got the impression this applies for function definitions, rather than calling. – jabozzo Sep 29 '16 at 02:38
0

Actually, you don't have to use self keyword unless you're consistent. Check out this example, where I changed self to test :

class funcs():
    def init(test, a, b):
        test.a=a
        test.b=b

    def plus(test):
        c = test.a + test.b
        print"%d + %d = %d" %(test.a, test.b, c)

    def minus(test):
        c = test.a - test.b
        print"%d - %d = %d" %(test.a, test.b, c)

obj = funcs()
obj.init(10, 6)
obj.plus()
obj.minus()

You can try to mix those instance name, so it won't be named self.

class A(object):
  def __init__(a_obj, foo):
    a_obj._foo = foo

class B(A):
  def __init__(self, test, foo):
    A.__init__(self, a_obj=test, foo=foo) # here you pass object of class B and actually another object of class B

a = A(2)
b = B(a, 1)

Giving output:

A.__init__(self, a_obj=test, foo=foo) 
TypeError: __init__() got multiple values for keyword argument 'a_obj'

I'm not sure what actually you want to accomplish by passing those object like this. In your code, self in class A and self in class B are not the same objects.

I suppose that here: A.__init__(self=self, foo=foo) you are doing something like A_instance=B_instance (self=self)

Jagoda Gorus
  • 329
  • 4
  • 18
  • I'm just calling the parent's `__init__`. I'm using this approach instead of using `super()` in order to control the `__init__` call order of the parents in multiple inheritance, just like this [http://stackoverflow.com/q/9575409/5705400]. So self in A and self in B should be the same object since im passing a reference of B to the `__init__` method of A. Which is okay since B inherits from A, so it's also an A. – jabozzo Sep 29 '16 at 20:52