I don't understand the behavior of arrays in classes when looping over over them in an array of objects.
Ok, let's say i have this code:
class example:
arr = []
def __init__(self):
self.arr.append(69)
examples = []
for i in range(5):
examples.append(example())
for e in examples:
for a in e.arr:
print(str(a))
Expected output is five 69s, but it prints 25 of them. Why?
EDIT: I've somehow figured out that all the instances use the SAME ARRAY, how is that possible if i used self
?
CodePudding user response:
example
has a list-valued class attribute, so all instances of example
share that same list. (You never assigned to self.arr
, so you did not create an instance attribute that shadows the class attribute.) If you had created one instance of example,
then example.arr
would have one element. If you had created 50 instances of example,
then example.arr
would have 50 elements.
As a resut, example.arr
contains 5 elements, because you created 5 instances of example
. (There aren't 5 objects each with a singleton list specific to it.) Your nested loop prints the full contents of a 5-element list 5 times, resulting in 25 lines of output.
What you likely intended was for your class to be defined as follows:
class Example:
def __init__(self):
self.arr = []
self.arr.append(69)
# Which would be the long way of writing
# self.arr = [69]
Now the code
examples = []
for i in range(5):
examples.append(example())
would give you a list of objects whose arr
attribute each contains a single element, and
for e in examples:
for a in e.arr:
print(str(a))
would iterate over the distinct singleton list of each object, producing the expected 5 lines of output.
CodePudding user response:
You are appending 69
to arr
5 times while simultaneously appending the class to examples
list. If you try this:
class example:
arr = []
def __init__(self):
self.arr.append(69)
print(self.arr)
You can see that your arr
already has 69
5 times.
Then, when you append the example
class to your list it keeps on appending the class, however simultaneously the example
class keeps on updating. Your current examples
list outputs this:
[<__main__.example object at 0x000001A2026EFAF0>, <__main__.example object at 0x000001A2026EFAC0>, <__main__.example object at 0x000001A2026EFA90>, <__main__.example object at 0x000001A2026EF8B0>, <__main__.example object at 0x000001A2026EF730>]
This whole list contains of the example class which has been lately updated to the arr
containg 69
5 times.
To make your code functional with OOP try this:
class example:
arr = []
def __init__(self):
self.arr.append(69)
examples = []
for i in range(5):
example.arr = []
examples.append(example())
for e in examples:
for a in e.arr:
print(a)
Edit: Thanks to @chepner for the clarification of OP's requirement.
CodePudding user response:
As you are updating the class variable each time, the arr it holds number if time it got inserted. To avoid the behaviour, try the below if this was your intention.
class example:
#arr = []
def __init__(self):
self.arr = []
self.arr.append(69) ## now that the self.arr is defined it acts as object variable, else it will try to find the variable in the class.
examples = []
for i in range(2):
examples.append(example())
for e in examples:
for a in e.arr:
print(str(a))
Please find the below reference, hope this helps: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
CodePudding user response:
example.arr
does only have 5 elements in it:
print(example.arr)
… but you’re iterating over example.arr
5 times (once for every one of the 5 example
objects in the examples
list)