0

Using the following code, when I create an instance and then append an item to a list on the instance attribute, the instance method doesn't notice the added item.

class Stuff:
    def __init__(self, stuff = []):
        self.stuff = stuff
        self.number_of_stuff = self.__len_stuff()

    def __len_stuff(self):
        return len(self.stuff)

# create an instance
some_stuff = Stuff(["notebook", "pencil", "eraser"])

# show stuff in instance
print(some_stuff.stuff)
# output: ['notebook', 'pencil', 'eraser']

# check how much stuff is in instance
print(some_stuff.number_of_stuff)
# output: 3

# add more stuff to instance
some_stuff.stuff.append("fidget spinner")
print(some_stuff.stuff)
# output: ['notebook', 'pencil', 'eraser', 'fidget spinner']

# check how much stuff is in instance again
print(some_stuff.number_of_stuff)
# output: 3

I am so confused by this. What is the proper way to append an item to an instance attribute list? It is as if somehow the instance method "can't see" all of the items in the list.

3
  • 1
    Why do you expect this to work? You only set the number_of_stuff property when the object is first initialised - it is never changed afterwards. Commented Oct 6, 2018 at 20:48
  • 2
    (Also you've got a mutable default argument, which will cause other problems, but is not the cause of this specific problem.) Commented Oct 6, 2018 at 20:48
  • @RobinZigmond I see where I went wrong. What I wanted was for the attribute to fill with the results of the method call, which is exactly what using @property achieves. Commented Oct 6, 2018 at 23:19

5 Answers 5

3

If you do want the number_of_stuff property to dynamically reflect the length of the stuff property, Python provides a way to do this with the property decorator:

@property
def number_of_stuff(self):
    return len(self.stuff)

This means that you can access a number_of_stuff property which automatically calls this method and returns the result.

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

1 Comment

Thank you, I realized that it probably had something to do with setting the @property but I now I actually understand :D
1

You are initializing self.number_of_stuff in your constructor. When you append to the list, you add fidget spinner to the list but do not update the number_of_stuffvariable. Printing len(some_stuff.stuff) will output 4 as you are expecting.

Comments

0

You are just printing out some_stuff.number_of_stuff which has been initialized to a value of 3 when you did print(some_stuff.number_of_stuff) in line 13. To get the updated value of 4, invoke the function to calculate the length again. Something like this will work

class Stuff:
    def __init__(self, stuff = []):
        self.stuff = stuff
        self.number_of_stuff = self.len_stuff()

    def len_stuff(self):
        return len(self.stuff)

# create an instance
some_stuff = Stuff(["notebook", "pencil", "eraser"])

# show stuff in instance
print(some_stuff.stuff)
# output: ['notebook', 'pencil', 'eraser']

# check how much stuff is in instance
print(some_stuff.number_of_stuff)
# output: 3

# add more stuff to instance
some_stuff.stuff.append("fidget spinner")
print(some_stuff.stuff)
# output: ['notebook', 'pencil', 'eraser', 'fidget spinner']

# check how much stuff is in instance again
print(some_stuff.len_stuff()) #recalculating length
# output: 4

Comments

0

You could set up 2 methods outside of your __init__ one to append to self.stuff and one to gather the amount of items.

class Stuff:
    def __init__(self, stuff = []):
        self.stuff = stuff

    def add_item(self, item):
        self.stuff.append(item)

    def no_items(self):
        return len(self.stuff)

some = Stuff(['notebook', 'pencil', 'eraser'])
print(some.stuff) # ['notebook', 'pencil', 'eraser']
print(some.no_items()) # 3

some.add_item('fidget spinner')
print(some.stuff) # ['notebook', 'pencil', 'eraser', 'fidget spinner']
print(some.no_items()) # 4

Comments

0

If what you want to do is having a list with editable attributes, you should create a class which inherits of the builtin list, instead of having a list in the class.

class Stuff(list):
    def __init__(self, lst, another_stuff=None):
        super().__init__(lst)
        self.another_stuff = another_stuff

Then you get an object which behave exactly like a list, but which also has an another_stuff attribute:

>>> l = Stuff(['a', 'b', 'c', 'd'], another_stuff=42)
>>> l
['a', 'b', 'c', 'd']
>>> l.append('z')
>>> l
['a', 'b', 'c', 'd', 'z']
>>> len(l)
5
>>> l.another_stuff
42

Comments

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.