Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new rule to prevent nested list footgun #10505

Open
qexat opened this issue Mar 21, 2024 · 3 comments
Open

Add new rule to prevent nested list footgun #10505

qexat opened this issue Mar 21, 2024 · 3 comments
Labels
rule Implementing or modifying a lint rule

Comments

@qexat
Copy link

qexat commented Mar 21, 2024

Hello.

I don't really work with nested lists but I know that it's quite common among the sci community (in fact I'm opening this issue after seeing this tweet).

I dug into the tracker to see if it was suggested before, but I could not find anything. I forgot to record what I tried, though.

Anyway, here is an excerpt of the issue:

# It might not be intuitive that the lists inside are actually the same
# It is very likely not to be intended, and a footgun all the time
foo: list[list[int]] = [[]] * 4

foo[0].append(42)

print(foo)  # [[42], [42], [42], [42]]

It's quite silly and experienced Python programmers usually don't fall for it, but people for whom coding is not their main activity and/or beginners can and do.

This rule could also be extended to passing a list literal as the second argument of dict.fromkeys, although this might be considered out of this issue's scope.
(+ I don't know by heart all the places where this "lists that actually share the same memory" footgun appears, but feel free to list some more.)

@MichaReiser MichaReiser added the rule Implementing or modifying a lint rule label Mar 21, 2024
@boolean-light
Copy link
Contributor

Happens for all kinds of mutable, so we could add rules for those included:

foo = [set()] * 4
foo[0].add(42)
print(foo)  # [{42}, {42}, {42}, {42}]

bar = [{}] * 4
bar[0]["a"] = 42
print(bar)  # [{'a': 42}, {'a': 42}, {'a': 42}, {'a': 42}]

@qexat
Copy link
Author

qexat commented Mar 21, 2024

Dang it, I missed this discussion. I really am terrible at searching up.
But yeah, of course, any mutable non-scalar object should be included.

@pankdm
Copy link

pankdm commented Nov 10, 2024

I think it might be pretty hard to detect really dangerous examples of that with high precision. Looking at https://grep.app/search?q=%5B%5B%5D%5D%20%2A&case=true&filter[lang][0]=Python there are plenty of usages, but they all look fine.
Someone needs to do

foo[0].append(bar)

to make it a real footgun.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rule Implementing or modifying a lint rule
Projects
None yet
Development

No branches or pull requests

4 participants