-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add description for fix-mutable-params
- Loading branch information
Showing
1 changed file
with
52 additions
and
0 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
src/codemodder/codemods/docs/pixee_python_fix-mutable-params.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
Using mutable values for default arguments is not a safe practice. | ||
Look at the following very simple example code: | ||
|
||
```python | ||
def foo(x, y=[]): | ||
y.append(x) | ||
print(y) | ||
``` | ||
|
||
The function `foo` doesn't do anything very interesting; it just prints the | ||
result of `x` appended to `y`. Naively we might expect this to simply print an | ||
array containing only `x` every time `foo` is called, like this: | ||
|
||
```python | ||
>>> foo(1) | ||
[1] | ||
>>> foo(2) | ||
[2] | ||
``` | ||
|
||
But that's not what happens! | ||
|
||
```python | ||
>>> foo(1) | ||
[1] | ||
>>> foo(2) | ||
[1, 2] | ||
``` | ||
|
||
The value of `y` is preserved between calls! This might seem surprising, and it is. | ||
It's due to the way that scope works for function arguments in Python. | ||
|
||
The result is that any default argument value will be preserved between | ||
function calls. This is problematic for *mutable* types, including things | ||
like `list`, `dict`, and `set`. | ||
|
||
Relying on this behavior is unpredictable and generally considered to be | ||
unsafe. Most of us who write code like this were not anticipating the | ||
surprising behavior, so it's best to fix it. | ||
|
||
Our codemod makes an update that looks like this: | ||
```diff | ||
- def foo(x, y=[]): | ||
+ def foo(x, y=None): | ||
+ y = [] if y is None else y | ||
y.append(x) | ||
print(y) | ||
``` | ||
|
||
Using `None` is a much safer default. The new code checks if `None` is passed, | ||
and if so uses an empty `list` for the value of `y`. This will guarantee | ||
consistent and safe behavior between calls. |