Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of objects function not working

Sorry for the title, I hope it reflects correctly my problem :

In the following code, I was expecting the result to be result 0 1 2 but instead I have 2 2 2. The code inside my_function seems to be interpreted with the last instance of obj. What is wrong ?

class Example:
    def __init__(self, x):
        self.x = x

    def get(self):
        return self.x

a_list = []
for index in range(3):
    obj = Example(index)

    def my_function(x):
        #some stuff with x like obj.another_function(x)
        return obj.get()

    a_list.append(my_function)

for c in a_list:
    print(c())
like image 851
Benjamin Avatar asked Jun 23 '26 16:06

Benjamin


2 Answers

When you define this

def my_function():
    return obj.get()

Python will understand that my_function should run the get() method of an object called obj and return the value. It won't know the value of obj and what the get() method does until you attempt to call it.

So, you are actually defining three different functions that will eventually do the same thing. And, in the end, running the same code thrice.

But why is the return 2 2 2?

Because after the last iteration, the value of obj is Example(2)* because you redefine its value at every iteration, and the last one remains.

* because of this line obj = Example(index)

like image 57
rafaelc Avatar answered Jun 26 '26 09:06

rafaelc


Understanding a few things about how python works will help you understand what's happening here. Here obj is a closure, closures are evaluated at call time, not when the function is defined so if I do this:

x = "hello"
def printX():
    print x
x = "goodbye"
printX() # goodbye

I get "goodbye" because printX is referencing a global variable in my module, which changes after I create printX.

What you want to do is create a function with a closure that references a specific object. The functional way to do this is to create a function that returns another function:

x = "hello"
def makePrintX(a):
    def printX():
        # We print a, the object passed to `makePrintX`
        print a
    return printX

# x is evaluated here when it is still "hello"
myPrintX = makePrintX(x) 

x = "goodbye"
myPrintX() # "hello"

If you're having trouble understanding the above example I would recommend reading up on python's scoping rules. For your example, you could do something like this:

class Example:
    def __init__(self, x):
        self.x = x

    def get(self):
        return self.x

def makeObjFunction(obj):
    def objFunction(x):
        return obj.get()
    return objFunction

a_list = []
for index in range(3):
    obj = Example(index)
    my_function = makeObjFunction(obj)

    a_list.append(my_function)

for c in a_list:
    print(c("some value"))
like image 44
Bi Rico Avatar answered Jun 26 '26 08:06

Bi Rico



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!