Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a function inside a loop [duplicate]

Why is this not working ?

u = {}
for me in ['foo', 'bar']:
   def callback():
       return 'I am %s' % me
   u[me] = callback

The output I get is:

>>> u['foo']()
'I am bar'

It seems the callback is defined once at the latest iteration.

EDIT

As proposed by kawadhiya21, a class approach would work:

class CallbackFactory():
    def __init__(self, me):
       self.me = me

    def __call__(self):
       return 'I am %s' % self.me

u = {}
for me in ['foo', 'bar']:

   u[me] = CallbackFactory(me)

But it is far more complicated than the former approach.

like image 474
nowox Avatar asked Jun 06 '17 08:06

nowox


People also ask

Can you define a function inside a loop?

Accepted Answer "function" as a keyword is only used for defining functions, and cannot be used inside a loop (or inside an "if" or "switch" or other control statement.) The only kinds of functions that can be defined within loops are anonymous functions.

Can you define a function within a loop python?

Python call function inside for loop A Python for loop is used to loop through an iterable object (like a list, tuple, set, etc.) and perform the same action for each entry. We can call a function from inside of for loop.

Can a function be in a for loop?

When we log a function call expression the output is the return value of the function. We logged the return value of a self-invoking (it called itself) anonymous function expression. This proves that we can run a function inside a loop.

Can we call a function inside a for loop in C?

You should not define a function inside a loop because you'll encounter errors unless you add a check before the function declaration to see if the function already exists. if (menuSelect == 2); --> ; is not required in your case.


2 Answers

All your functions are referencing the same variable me. When you try and call the function, me has the value 'bar', because that's what it was when the loop ended.

If you want me to take a different value for each definition of the function, then each function needs its own copy of the variable.

u = {}
for me in ['foo', 'bar']:
   def callback(me_copy=me):
       return 'I am %s' % me_copy
   u[me] = callback

If you wanted, you could shorten that to:

u = {}
for me in ['foo', 'bar']:
   u[me] = lambda me_copy=me: 'I am %s'%me_copy

or even

u = { me: (lambda me_copy=me: 'I am %s'%me_copy) for me in ('foo', 'bar') }
like image 161
khelwood Avatar answered Sep 23 '22 00:09

khelwood


First off, in your example, u['foo'] should not return a string at all, but a function handle. :) EDIT: this sentence is no longer relevant.

Second, your function callback uses me, from the outer scope. If you change this value (in your case by your loop) in the outer scope, then the function's output also changes.

To fix this, you need to make me part of the function's own scope, e.g. by doing:

def callback(int_me=me):
    return 'I am %s' % int_me
like image 35
acdr Avatar answered Sep 20 '22 00:09

acdr