Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't call parent's method in list comprehension in child's initializer, but explicit loop works

The child class inherits from the parent class. Inside the constructor of child I am initializing a list-type member variablexs by repeatedly calling the member function foo() defined in parent. It turns out that if I initialize xs by explicitly looping and appending each value returned by foo(), everything works fine.

However, if I try to do the same thing within a list comprehension, I get a strange error thrown at me. Why does this error occur? What is the difference between a list comprehension in this case, and the explicit loop?

The MWE for the code that does work:

class parent(object):
    def __init__(self):
        self.x = 5

    def foo(self, a):
        return self.x


class child(parent):
    def __init__(self):
        super().__init__()

        self.xs = []
        for i in range(9):
            self.xs.append(super().foo(i))    

mychild = child()

The definition of child but with the list comprehension:

class child(parent):
    def __init__(self):
        super().__init__()
        self.xs = [super().foo(i) for i in range(9)]

The error in question:

% python test.py
Traceback (most recent call last):
  File "test.py", line 20, in <module>
    mychild = child()
  File "test.py", line 17, in __init__
    self.xs = [super().foo(i) for i in range(9)]
  File "test.py", line 17, in <listcomp>
    self.xs = [super().foo(i) for i in range(9)]
TypeError: super(type, obj): obj must be an instance or subtype of type
zsh: exit 1     python test.py
like image 819
mSSM Avatar asked Jul 01 '15 13:07

mSSM


People also ask

How do you call the function of parent class in child class?

You just have to create an object of the child class and call the function of the parent class using dot(.) operator.

Is list comprehension same as for loop?

List comprehensions are also more declarative than loops, which means they're easier to read and understand. Loops require you to focus on how the list is created. You have to manually create an empty list, loop over the elements, and add each of them to the end of the list.

Is it possible to use list comprehension with a string?

List comprehension works with string lists also. The following creates a new list of strings that contains 'a'. Above, the expression if 'a' in s returns True if an element contains a character 'a'.

Why list comprehension is faster than for loop?

List comprehensions are faster than for loops to create lists. But, this is because we are creating a list by appending new elements to it at each iteration.


1 Answers

List comprehensions are actually run in a separate scope (see e.g. Why is one class variable not defined in list comprehension but another is?), so the implicit form of super with no arguments won't work inside the list comprehension.

You have two options, assuming that you don't want to go back to the standard for loop:

  1. Use the explicit form of super, passing the class and instance arguments: super(child, self).foo(i); or
  2. As you've inherited foo from parent, just call it on the instance: self.foo(i).
like image 168
jonrsharpe Avatar answered Nov 15 '22 18:11

jonrsharpe