flake8-bugbear icon indicating copy to clipboard operation
flake8-bugbear copied to clipboard

False positive `B023` with loop's local variable

Open jamesbraza opened this issue 2 years ago • 3 comments

def some_fn(*_) -> None:
    ...


for _ in range(1):
    foo = 0
    some_fn(lambda: foo)

Since foo is a local variable in the loop, B023 shouldn't happen here (unless I am mistaken about something).

Running flake8==6.0.0 with flake8-bugbear==23.7.10 on this:

> flake8 a.py
a.py:7:21: B023 Function definition does not bind loop variable 'foo'.

I think this relates to https://github.com/PyCQA/flake8-bugbear/issues/269 or https://github.com/PyCQA/flake8-bugbear/issues/380.

jamesbraza avatar Jul 18 '23 23:07 jamesbraza

In your example it doesn't matter because foo is always assigned to the same value, but in general this isn't a false positive. For example, if you instead had foo = foo + 1, then every loop iteration would have a different value, and the lambda might close over the value and see an updated one.

JelleZijlstra avatar Jul 21 '23 17:07 JelleZijlstra

Thanks for the response, just trying to understand it more. The below code with foo = foo + 1 triggers B023 as well, though I believe it also doesn't have binding risk:

def some_fn(fn) -> None:
    print(fn())

foo = 0
for _ in range(10):
    foo = foo + 1  # foo is a local variable in the loop iteration
    some_fn(lambda: foo)

Would you mind clarifying your example? I am trying to understand the line between false positive and true positive here.

Also, if you think this issue should be closed out, feel free to close it

jamesbraza avatar Jul 21 '23 17:07 jamesbraza

If the function invocation is delayed (for whatever reason) you'd get an unexpected behaviour. For example:

foo = 0
fns = []
for _ in range(10):
    foo = foo + 1
    fns.append(lambda: print(foo))

for fn in fns:
    fn()  # all print 10

I suppose it would be pretty hard to verify if the lambda is only invoked within the same iteration

tomasr8 avatar Jul 27 '23 19:07 tomasr8