Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I iterate over locals() and within the iteration use returned item as a key?

I have a module named Promotions with some functions, and I have a variable that stores a list of all the functions containing "_promo" in the name.

promos = [
    locals()[name] for name in locals() # Iterate over each name in the dictionary returned by locals()
    if name.endswith("_promo") # Select only names that end with the _promo suffix.
    ] 

When I import Promotions in another place and ask to retrieve promos, I get a KeyError.

However, if I do the same thing but replace locals() with globals(), I don't get a KeyError.

Does anyone know why?

edit: Is it because the second time I call locals() (in locals()[name]) I am no longer in the same scope?

like image 829
Hannes Ziegler Avatar asked Oct 25 '25 14:10

Hannes Ziegler


1 Answers

Is it because the second time I call locals() (in locals()[name]) I am no longer in the same scope?

That's exactly the case. List comprehension have it's own scope just like a function, but the iterator over locals() is created in the outer scope.

import inspect

class LoudIterable:
    def __iter__(self):
        print(inspect.currentframe())
        return iter([1, 2])

x = [print(inspect.currentframe()) for i in LoudIterable()]

# <frame at 0x0000021795BFD4B8, file '', line 5, code __iter__>
# <frame at 0x0000021795CF8AF8, file '', line 8, code <listcomp>>
# <frame at 0x0000021795CF8AF8, file '', line 8, code <listcomp>>

You'll see that the each iteration has the same frame, but the __iter__ was called in an another frame.

And that makes sense when you think about generators.

non_iterable = 2
x = (i for i in non_iterable)

The iter is called on the iterable in an eager way, even though we haven't even started the iteration, you'll see the error straight away: TypeError: 'int' object is not iterable

Anyway, the easy fix is this:

promos = [v for k, v in locals().items() if k.endswith("_promo")]
like image 110
RafalS Avatar answered Oct 28 '25 05:10

RafalS



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!