Reputation: 13
Am new to python and was wondering difference between having an empty array as global or local variable when returning the array.
import collections
def check_duplicates(data: list) -> list:
dupes = []
for i in data:
if data.count(i) > 1:
dupes.append(i)
return dupes
if __name__ == "__main__":
assert list(check_duplicates([1, 2, 3, 4, 5])) == [],
Your Result:[]
Right Result:[]
import collections
dupes = []
def check_duplicates(data: list) -> list:
for i in data:
if data.count(i) > 1:
dupes.append(i)
return dupes
if __name__ == "__main__":
assert list(check_duplicates([1, 2, 3, 4, 5])) == [],
Your result:[1,3,1,3]
Right result:[]
Originally I had the array outside of the function and was unable to return an empty array and was wondering
Upvotes: 1
Views: 66
Reputation: 6246
Alright, so first things first, the original code behaves correctly for how its written (but not in the way you wanted it), and will stop giving empty arrays once you run it for a list that produces a non empty array. The only thing left is to understand why it behaved the way it did.
Explanation
First, lists are mutable datatypes.
a = [1,2] #create a list object and bind it to the name a
b = a #both b and a are now referring to the same list object
a.append(3) #the list object a was referring to has been changed inplace, or mutated.
#notice that coincidentally b was referring to this same object
print(a) #Prints: [1,2,3]
print(b) #Prints: [1,2,3]
What that means is that if you use a list's method to make changes, such as .append
, it will change the list object inplace, and all names (such as a
or b
) referring to it will reflect the change.
Second, Your original code, with some comments
dupes = [] #create an empty list, and have the name dupes refer to the list object
def check_duplicates(data: list) -> list:
for i in data:
if data.count(i) > 1:
dupes.append(i) #mutate the list object that dupes was referring to.
return dupes #return the list object dupes was referring to.
What is important is to realise that throughout the entire function, you never reassign the name dupes
so it continues to refer to the same list object. What it results in is behaviour as follows:
dupes = []
def check_duplicates(data: list) -> list:
for i in data:
if data.count(i) > 1:
dupes.append(i)
return dupes
check_duplicates([1])
print(dupes) #[]
check_duplicates([2])
print(dupes) #[]
check_duplicates([1, 1])
print(dupes) #[1, 1]
check_duplicates([2])
print(dupes) #[1, 1] !!!! The dupes list continues to refer to the object, and any further append calls just add to it
check_duplicates([99, 99, 100, 100])
print(dupes) #[1, 1, 99, 99, 100, 100]
check_duplicates([2])
print(dupes) #[1, 1, 99, 99, 100, 100]
Hopefully that makes it clearer. the dupes
name will continue to refer to the list that is being mutated inside the function, and this is why unless you reassign dupes
to a new empty list inside, you will continue to get the old results. Hope this helps.
Good further reading.
Upvotes: 2