I am trying to solve the classic FizzBuzz problem
- Print all numbers from 1 to N
- But, if divisible by 3, then prompt "Fizz" instead
- But, if divisible by 5, then prompt "Buzz" instead
- But, if divisible by 3 and 5, then prompt "FizzBuzz" instead
- But, if divisible by m, then etc ....
in Python in a lot of exotic ways. One of them was to create from a dictionary a list of functions to apply on the N numbers. But I encountered an unexpected behaviour. I created in a for loop a list of 3 lambda functions. Their id is different, but they all behave as the last created function. I know that dealing with mutable objects in list can be tricky but I can't understand that behaviour. The best is to show you the code:
data = {3: "Fizz",
5: "Buzz",
7: "Bazz",}
def closures_on_dict(dictionnaire):
"""Create a list of functions x->f(x) from a dictionary
The int key being a divisor, the string value being the prompted value
if x is divisible by the divisor"""
functions = list()
ii = 0
for divisor, sentance in dictionnaire.items():
print(f"divisor id: {(divisor)}, sentance id: {id(sentance)}")
functions += [lambda x: sentance if x%divisor == 0 else x]
print(f"function id: {id(functions[ii])}")
ii +=1
return functions
###############################################################################
if __name__=="__main__":
functions = closures_on_dict(data)
for ii, function in enumerate(functions):
print(f"function[{ii}] id is: {id(function)}")
for test in data.keys():
print(f"\t function[{ii}]({test}) = {function(test)}")
And the result is ...
divisor id: 3, sentance id: 140444073732784
function id: 140444096066176
divisor id: 5, sentance id: 140444073732016
function id: 140444096066752
divisor id: 7, sentance id: 140444072258672
function id: 140444096065600
function[0] id is: 140444096066176
function[0](3) = 3
function[0](5) = 5
function[0](7) = Bazz
function[1] id is: 140444096066752
function[1](3) = 3
function[1](5) = 5
function[1](7) = Bazz
function[2] id is: 140444096065600
function[2](3) = 3
function[2](5) = 5
function[2](7) = Bazz
So their id are different but they all works the same. Obviously their is an easy workaround :
def dirty_patch(key, value):
return lambda x: value if x%key == 0 else x
And then it works perfectly:
function[0] id is: 140444096048576
function[0](3) = Fizz
function[0](5) = 5
function[0](7) = 7
function[1] id is: 140444096049008
function[1](3) = 3
function[1](5) = Buzz
function[1](7) = 7
function[2] id is: 140444096217440
function[2](3) = 3
function[2](5) = 5
function[2](7) = Bazz
But I would like to understand why, when I'm creating the lambda functions inside closures_on_dict(), and even having a different id, they behave the same ? I assume it has something to do with mutable arguments "divisor" and "sentance" in the for loop but I'm not skilled enough in Python to understand where is the problem.