Skip to content
New issue

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

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

Already on GitHub? # to your account

Ideas for new lints around iteration #7783

Open
alexprengere opened this issue Oct 3, 2023 · 5 comments
Open

Ideas for new lints around iteration #7783

alexprengere opened this issue Oct 3, 2023 · 5 comments
Labels
accepted Ready for implementation rule Implementing or modifying a lint rule

Comments

@alexprengere
Copy link

I apologize if you not looking for new lints to implement in Ruff.

I do a fair share of code reviews, and I quite often stumble on these issues which are not caught by any linter AFAICT (flake8, pylint, refurb, ruff). I am not sure how hard those would be to implement, as for the first one you would need some type inference.

a = [1, 2]
b = [3, 4]

# Not good
for x in a + b:
    print(x)

# Better but not really good either
for x in *a, *b:
    print(x)

# Best
for x in itertools.chain(a, b):
    print(x)

This happens really often when people want to iterate on multiple lists, tuples, etc.
Another one in a similar spirit:

a = [1, 2]
b = [3, 4]
c = [a, b]

# Not good
for x in itertools.chain(*c):
    print(x)

# Better
for x in itertools.chain.from_iterable(c):
    print(x)
@charliermarsh
Copy link
Member

Thanks! One question -- given:

# Not good
for x in a + b:
    print(x)

When would it be invalid to rewrite as itertools.chain(a, b)?

@charliermarsh charliermarsh added the needs-info More information is needed from the issue author label Oct 3, 2023
@alexprengere
Copy link
Author

If you are sure a and b are lists or tuples, I think it is never invalid to rewrite.
It can be invalid on classes that would be iterable but also implement some type of addition that is not concatenation, like a numpy matrix:

import numpy as np

a = b = np.matrix([[1,2], [3,4]])

for x in a + b:
    print(x)
# [[2 4]]
# [[6 8]]

for x in itertools.chain(a, b):
    print(x)
# [[1 2]]
# [[3 4]]
# [[1 2]]
# [[3 4]]

@charliermarsh
Copy link
Member

Thanks, that makes sense. We do have the ability to do limited within-file inference for lists, tuples, sets, and dictionaries, with the downside that the inference can lead to false-negatives (but is a reasonable fit for rules like this).

@charliermarsh charliermarsh added rule Implementing or modifying a lint rule accepted Ready for implementation and removed needs-info More information is needed from the issue author labels Oct 3, 2023
@Skylion007
Copy link
Contributor

flake8-simplify or flake8-comprehensions may be interested in this rule as well.

@Avasam
Copy link
Contributor

Avasam commented Oct 12, 2023

Idk how complete it is, but refurb added itertool.chain related checks lately: dosisod/refurb#293

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
accepted Ready for implementation rule Implementing or modifying a lint rule
Projects
None yet
Development

No branches or pull requests

4 participants