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
You just have to create an object of the child class and call the function of the parent class using dot(.) operator.
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.
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'.
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.
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:
super
, passing the class and instance arguments: super(child, self).foo(i)
; orfoo
from parent
, just call it on the instance: self.foo(i)
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With