Skip to content

List/Set in default argument of function not recreated each function call unlike string #127792

Closed as not planned
@jimtremblay

Description

@jimtremblay

Bug report

Bug description:

def f1(s=''):
    print(f'f1: {s}')
    s += 'a'
    return s

def f2(l=[]):
    print(f'f2: {l}')
    l.append('a')
    return l

def f3(s=set()):
    print(f'f3: {s}')
    s.add('a')
    return s

for i in range(4):
    print(f'1a: {i}')
    print(f'1b: {f1()}')

for i in range(4):
    print(f'2a: {i}')
    print(f'2b: {f2()}')

for i in range(4):
    print(f'3a: {i}')
    print(f'3b: {f3()}')

Executing this code in python 3.13.0 will show you this output:

1a: 0
f1: 
1b: a
1a: 1
f1: 
1b: a
1a: 2
f1: 
1b: a
1a: 3
f1: 
1b: a
2a: 0
f2: []
2b: ['a']
2a: 1
f2: ['a']
2b: ['a', 'a']
2a: 2
f2: ['a', 'a']
2b: ['a', 'a', 'a']
2a: 3
f2: ['a', 'a', 'a']
2b: ['a', 'a', 'a', 'a']
3a: 0
f3: set()
3b: {'a'}
3a: 1
f3: {'a'}
3b: {'a'}
3a: 2
f3: {'a'}
3b: {'a'}
3a: 3
f3: {'a'}
3b: {'a'}

As you can see, a new string is created for each call of f1 but no new list for f2 or no new set for f3.

I was expecting something like:

1a: 0
f1: 
1b: a
1a: 1
f1: 
1b: a
1a: 2
f1: 
1b: a
1a: 3
f1: 
1b: a
2a: 0
f2: []
2b: ['a']
2a: 1
f2: []
2b: ['a']
2a: 2
f2: []
2b: ['a']
2a: 3
f2: []
2b: ['a']
3a: 0
f3: set()
3b: {'a'}
3a: 1
f3: set()
3b: {'a'}
3a: 2
f3: set()
3b: {'a'}
3a: 3
f3: set()
3b: {'a'}

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions