Skip to content
Advertisement

Why does this program call the wrong method? [Python, MultiTimer library]

I ran into a bizarre issue while trying to structure my code as follows:

At the beginning, the program starts n multi timers that repeatedly call methods m_1 to m_n every t_1 to t_n seconds.

To implement this, I use the MultiTimer library (https://pypi.org/project/multitimer/). For flexibility I define a named tuple at the start of the program that contains the method, whether or not it is enabled and the frequency with which it should be called.

I assume the issue is in how I use the named tuple, but I can’t seem to figure out what the problem is.

BotSettings = namedtuple(
    "BotSettings", ["method", "enabled", "repeat_every_x_seconds"])
bot_list = [
    BotSettings(method=bots.accept_pending_invites,
                enabled=True, repeat_every_x_seconds=10),
    BotSettings(method=bots.handle_cat_requests,
                enabled=True, repeat_every_x_seconds=10),
    BotSettings(method=bots.handle_confession_requests,
                enabled=True, repeat_every_x_seconds=10)
]
timers = [MultiTimer(bot.repeat_every_x_seconds, lambda: bot.method(
        client), runonstart=True) for bot in bot_list if bot.enabled]
for timer in timers:
    timer.start()

The output of the above program is as follows:

handle confession requests called
handle confession requests called
handle confession requests called

Another observation I made is that the program always calls the last method in bot_list num_enabled times where num_enabled is the number of methods in bot_list with enabled=True.

Advertisement

Answer

Replace the lambda with function and pass arguments using kwargs. I used this code to test.

from multitimer import MultiTimer

def accept_pending_invites(client): print('invite', client)
def handle_cat_requests(client): print('cat', client)
def handle_confession_requests(client): print('confess', client)

bot_list=[
{ 'method':accept_pending_invites, 'enabled':True, 'repeat_every_x_seconds':10},
{ 'method':handle_cat_requests,'enabled':True, 'repeat_every_x_seconds':10},
{ 'method':handle_confession_requests, 'enabled':True, 'repeat_every_x_seconds':10}
]

timers = [MultiTimer(bot['repeat_every_x_seconds'], function=bot['method'], runonstart=True, kwargs={'client':123}) for bot in bot_list]
for timer in timers:
    timer.start()

Output

invite 123
cat 123
confess 123
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement