Skip to content

Conversation

@KanchiShimono
Copy link
Contributor

@KanchiShimono KanchiShimono commented May 2, 2025

Motivation and Context

Some functions and methods were using mutable objects (typically dict) as default argument values.
In Python, default arguments are evaluated only once at the time of function definition.
This can lead to unexpected behavior when the default value is modified within the function, as subsequent calls to the function may reuse the modified object.

As a result, calling such functions or methods multiple times can lead to unintended behavior.

Reference:
8.7. Function definitions (Official Python Documentation)

Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter value is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default parameter value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

Description

  • Replaced mutable types (e.g., dict, list) used as default argument values with None, and properly initialized them within the function body.
  • Reviewed and updated the parts of the code that performed destructive modifications on the arguments, to avoid unintentionally modifying variables from the caller’s scope.
  • Added the flake8-bugbear rule in Ruff to detect this kind of issue.
    • For now, errors in tests and samples directories are ignored due to the large number of violations.

Contribution Checklist

@KanchiShimono KanchiShimono requested a review from a team as a code owner May 2, 2025 02:26
@markwallace-microsoft markwallace-microsoft added the python Pull requests for the Python Semantic Kernel label May 2, 2025
@github-actions github-actions bot changed the title Replace mutable default arguments and prevent unintended side effects Python: Replace mutable default arguments and prevent unintended side effects May 2, 2025
@KanchiShimono KanchiShimono force-pushed the replace-mutable-default-args branch from 2075d22 to f70e026 Compare May 2, 2025 02:52
Copy link
Collaborator

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the improvements, @KanchiShimono.

@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented May 2, 2025

Python Unit Test Overview

Tests Skipped Failures Errors Time
3467 5 💤 0 ❌ 0 🔥 1m 52s ⏱️

@KanchiShimono
Copy link
Contributor Author

I’ve configured the project to ignore the Ruff rule (B009) that conflicts with mypy checks.
I also confirmed that the previously failing tests now pass in my local environment.

@KanchiShimono KanchiShimono force-pushed the replace-mutable-default-args branch from dbb003c to 4ade63f Compare May 2, 2025 12:28
@eavanvalkenburg eavanvalkenburg enabled auto-merge May 6, 2025 19:02
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue May 6, 2025
github-merge-queue bot pushed a commit that referenced this pull request May 6, 2025
… effects (#11849)

### Motivation and Context

Some functions and methods were using mutable objects (typically `dict`)
as default argument values.
In Python, default arguments are evaluated only once at the time of
function definition.
This can lead to unexpected behavior when the default value is modified
within the function, as subsequent calls to the function may reuse the
modified object.

As a result, calling such functions or methods multiple times can lead
to unintended behavior.

Reference:  
[8.7. Function definitions (Official Python
Documentation)](https://docs.python.org/3.12/reference/compound_stmts.html#function-definitions)
> Default parameter values are evaluated from left to right when the
function definition is executed. This means that the expression is
evaluated once, when the function is defined, and that the same
“pre-computed” value is used for each call. This is especially important
to understand when a default parameter value is a mutable object, such
as a list or a dictionary: if the function modifies the object (e.g. by
appending an item to a list), the default parameter value is in effect
modified. This is generally not what was intended. A way around this is
to use None as the default, and explicitly test for it in the body of
the function, e.g.:


### Description

- Replaced mutable types (e.g., `dict`, `list`) used as default argument
values with `None`, and properly initialized them within the function
body.
- Reviewed and updated the parts of the code that performed destructive
modifications on the arguments, to avoid unintentionally modifying
variables from the caller’s scope.
- ~Added the `flake8-bugbear` rule in Ruff to detect this kind of
issue.~
- ~For now, errors in `tests` and `samples` directories are ignored due
to the large number of violations.~

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
Merged via the queue into microsoft:main with commit 966fa8c May 6, 2025
28 checks passed
@github-project-automation github-project-automation bot moved this to Sprint: Done in Semantic Kernel May 6, 2025
@KanchiShimono KanchiShimono deleted the replace-mutable-default-args branch May 9, 2025 08:58
jcruzmot-te pushed a commit to thousandeyes/aia-semantic-kernel that referenced this pull request Sep 15, 2025
… effects (microsoft#11849)

### Motivation and Context

Some functions and methods were using mutable objects (typically `dict`)
as default argument values.
In Python, default arguments are evaluated only once at the time of
function definition.
This can lead to unexpected behavior when the default value is modified
within the function, as subsequent calls to the function may reuse the
modified object.

As a result, calling such functions or methods multiple times can lead
to unintended behavior.

Reference:  
[8.7. Function definitions (Official Python
Documentation)](https://docs.python.org/3.12/reference/compound_stmts.html#function-definitions)
> Default parameter values are evaluated from left to right when the
function definition is executed. This means that the expression is
evaluated once, when the function is defined, and that the same
“pre-computed” value is used for each call. This is especially important
to understand when a default parameter value is a mutable object, such
as a list or a dictionary: if the function modifies the object (e.g. by
appending an item to a list), the default parameter value is in effect
modified. This is generally not what was intended. A way around this is
to use None as the default, and explicitly test for it in the body of
the function, e.g.:


### Description

- Replaced mutable types (e.g., `dict`, `list`) used as default argument
values with `None`, and properly initialized them within the function
body.
- Reviewed and updated the parts of the code that performed destructive
modifications on the arguments, to avoid unintentionally modifying
variables from the caller’s scope.
- ~Added the `flake8-bugbear` rule in Ruff to detect this kind of
issue.~
- ~For now, errors in `tests` and `samples` directories are ignored due
to the large number of violations.~

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants