0

I cannot understand why I cannot reference the integer member of the nested class in the lambda. The following code demonstrates the failure. The same reference is used in the print prior to the reduce command with no issue.

Is there some subtlety I'm missing?

from functools import reduce

class B :

    def __init__(self, n) :
        self.length = n


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


myList = [A(1), A(5), A(7)]

print( myList[0].b.length )
print( reduce(lambda a, b : a.b.length + b.b.length, myList) )

I was expecting the lambda in the reduce to add the numbers contained in the listed class. I searched but could find the terminology that would yield an explanation to the problem I am experiencing. The output below shows the error. Any help is appreciated.

1
Traceback (most recent call last):
  File "main.py", line 20, in <module>
    print( reduce(lambda a, b : a.b.length + b.b.length, myList) )
  File "main.py", line 20, in <lambda>
    print( reduce(lambda a, b : a.b.length + b.b.length, myList) )
AttributeError: 'int' object has no attribute 'b'

3 Answers 3

3

Nesting isn't the problem. A list of B instances would have the same issue.

The reduce function would need to return an instance of the A class to continue accessing .b.length, otherwise, it returns an int, then tries to compute the sum of the first two elements to the next instance, so <type: int> + b.b.length for the remainder of the list.

You're looking just for sum(x.b.length for x in myList)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the quick reply. I think your alternate solution of just using the sum to achieve this would work best in what I am trying to do.
I agree with the sum() approach, but I think you didn't explain the problem OP is facing clearly. It's a bit too technical to understand.
-1

The problem is this: the first time you call reduce(), it works as expected, adding the .length attribute of a.b. However, the second iteration breaks, because by now the first element of the list is an integer object of value 6. Integer objects don't have an attribute named b, so it raises an AttributeError.

There are some workaround for this:

  • Use sum():
class B:

    def __init__(self, n):
        self.length = n


class A:

    def __init__(self, n):
        self.b = B(n)


myList = [A(1), A(5), A(7)]

print(myList[0].b.length)

print(sum(a.b.length for a in myList))
  • Use for-loop:
class B:

    def __init__(self, n):
        self.length = n


class A:

    def __init__(self, n):
        self.b = B(n)


myList = [A(1), A(5), A(7)]

print(myList[0].b.length)



s = 0
for l in myList:
    s += l.b.length
  • Finally, you can still use reduce() if you want to, but you need to check the type of the arguments to your lambda first:
from functools import reduce


class B:

    def __init__(self, n):
        self.length = n


class A:

    def __init__(self, n):
        self.b = B(n)


myList = [A(1), A(5), A(7)]

print(myList[0].b.length)
print(reduce(lambda a, b: a.b.length + b.b.length if isinstance(a, A) else a + b.b.length, myList))

This approach s slightly more verbose, but it's the closest to your original code.

Comments

-2

you can try this,

print( reduce(lambda a, b : A(a.b.length + b.b.length), myList).b.length )

So, in your code the problem is when you are using reduce you are getting an integer but next value is again an instance of class-A, and the integer won't have any attribute(b), which is why you are getting an error.

To resolve this while reducing I'm creating an instance of class A again, so after reducing you'll get output in form of an instance of class A and you can retrieve length by simply calling (reduce output).b.length

3 Comments

Although this approach works, it create unnecessary objects that waste memory, especially if the list is large. In this case, the list is short, but suppose a list of 10,000 elements (not too large in some programming domains), then you'll have a serious memory problem.
A novel approach, that took a little staring to understand. Thanks for that. I think I'm going to stick to OneCricketeer's solution since its easier to read and aligns with what I am trying to do. Your solution does a good job highlighting the cause of the error more clearly.
don't post images of code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.