classification
Title: Optional List Args Persist Across Objects
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eric.smith, rosadenderon, steven.daprano
Priority: normal Keywords:

Created on 2020-11-16 20:37 by rosadenderon, last changed 2020-11-16 21:22 by steven.daprano. This issue is now closed.

Files
File name Uploaded Description Edit
PythonObjectListIssue.py rosadenderon, 2020-11-16 20:37 Program Demonstrating List Persistence Over Multiple Objects
Messages (5)
msg381153 - (view) Author: Rose Ridder (rosadenderon) Date: 2020-11-16 20:37
When creating several objects in one program, if there are lists passed into functions as optional arguments, those lists are persistent across all objects.
msg381154 - (view) Author: Rose Ridder (rosadenderon) Date: 2020-11-16 20:41
Including script explicitly:


# -*- coding: utf-8 -*-

class Obj:
    def __init__(self, num):
        self.num = num
        self.var = self.funct()
        
    def funct(self, array = []):
        print (array)
        array = [1,2,3]
        return array
    
    
    
def main():
    obj1 = Obj(1)
    print (obj1.num, obj1.var) # prints: 1 [1, 2, 3]


    obj2 = Obj(2)
    
    print (obj1.num, obj1.var) # prints: 1 [1, 2, 3, 1, 2, 3]
    print (obj2.num, obj2.var) # prints: 2 [1, 2, 3, 1, 2, 3]
    
    
if __name__ == "__main__": 
    main()
msg381156 - (view) Author: Rose Ridder (rosadenderon) Date: 2020-11-16 20:49
Sorry, incorrect code pasted in. The full comment and code is below:

When creating several objects in one program, if there are lists passed into functions as optional arguments, those lists are persistent across all objects.

# -*- coding: utf-8 -*-

class Obj:
    def __init__(self, num):
        self.num = num
        self.var = self.funct()
        
    def funct(self, array = []):
        array += [1,2,3] # issue also occurs with .append()
        return array
    
    
    
def main():
    obj1 = Obj(1)
    print (obj1.num, obj1.var) # prints: 1 [1, 2, 3]

    obj2 = Obj(2)
    
    print (obj1.num, obj1.var) # prints: 1 [1, 2, 3, 1, 2, 3]
    print (id(obj1), id(obj1.var)) # prints a unique address for obj1, but the address for the var attribute is the same as for obj2
    print (obj2.num, obj2.var) # prints: 2 [1, 2, 3, 1, 2, 3]
    print (id(obj2), id(obj2.var)) # prints a unique address for obj2, but the address for the var attribute is the same as for obj1
    
    
if __name__ == "__main__": 
    main()
msg381157 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2020-11-16 20:55
This is defined behavior in the language, so it's not a bug. The "pythonic" way to deal with this is usually:

def funct(self, array = None):
    if array is None:
         array = []
msg381159 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-11-16 21:22
Hi Rose, this is a FAQ:

https://docs.python.org/3/faq/programming.html#why-are-default-values-shared-between-objects

although it's also a feature that does cause beginners some trouble, see for example my comment here for more information:

https://bugs.python.org/msg361451
History
Date User Action Args
2020-11-16 21:22:34steven.dapranosetnosy: + steven.daprano
messages: + msg381159
2020-11-16 20:55:51eric.smithsetstatus: open -> closed

components: + Interpreter Core, - ctypes

nosy: + eric.smith
messages: + msg381157
resolution: not a bug
stage: resolved
2020-11-16 20:49:02rosadenderonsetmessages: + msg381156
2020-11-16 20:41:19rosadenderonsetmessages: + msg381154
2020-11-16 20:37:40rosadenderoncreate