0

In Python, is there a difference between the following two codes both of which gives the same result c = [0,-10]?

def foo1():
    a = [0,1]

    def foo2():
        a[1] = -10

    foo2()
    return a


c = foo1()

and

def foo1():
    a = [0,1]

    def foo2(b):
        b[1] = -10

    foo2(a)
    return a


c = foo1()

Some commentator suggests this is answered by this question. But it does not since my question asks about the passing of variables through an inner function whilst the linked question does not.

Hans
  • 1,269
  • 3
  • 19
  • 38
  • Does this answer your question? [Understanding variable scope in nested functions in Python](https://stackoverflow.com/questions/56303426/understanding-variable-scope-in-nested-functions-in-python) – Jab Jul 23 '20 at 22:39
  • 2
    Well, it's doing the same thing in two different ways. – juanpa.arrivillaga Jul 23 '20 at 22:45
  • @Jab: It does not answer my question. It shows the difference in the scope of the variables but says nothing about transmitting variables. – Hans Jul 23 '20 at 22:52
  • @juanpa.arrivillaga: You are saying option 1 is better because it is more succinct, right? – Hans Jul 23 '20 at 22:53
  • What exactly do you mean by "transmitting" You're not "transmitting" anything here. You're essentially asking if there's a difference between passing a variable to a function vs using the local variable you would have passed anyway which both examples have access to already. This is not a very good example as there's no need to use the nested function here at all. – Jab Jul 23 '20 at 22:55
  • Yes, there is a difference between the two codes (as previous answers mentioned). Please clarify more your question (what is the measure and importance of difference and sameness).. E.g. I guess there is reference counts increase in the second code – Jan Stránský Jul 23 '20 at 22:59
  • @jab: Yes, I meant "passing" variables --- I did not use the conventional word. Yes, your rephrasing of my question is correct. But that link you provided does not answer this question. – Hans Jul 23 '20 at 22:59
  • @Hans no, that's not what I'm saying at all. I'm saying, those are two different ways of doing the same thing. This is a toy example, so it's hard to say which is a *better* approach. I mean, the better approach would be to remove the unnecessary inner function altogether! There would need to be a more realistic context for me to have a strong opinion, but generally I would favor passing arguments explicitly. – juanpa.arrivillaga Jul 23 '20 at 23:05
  • @juanpa.arrivillaga: Understood and agree. – Hans Jul 23 '20 at 23:06
  • The difference is that in the second version, you can call `foo2()` with different variables as the argument, so it's more general. The first version is hard-coded to only work with the `a` variable. – Barmar Jul 23 '20 at 23:27
  • It's the same reason that parameters are generally preferred over global variables, it's more flexible. – Barmar Jul 23 '20 at 23:27
  • @Barmar: I am not sure it the second version is more general, because both 'b' and 'a' in 'foo2()' point to and are but two names of the same variable and changing one changes the other. – Hans Jul 25 '20 at 16:45
  • `b` only refers to the outer `a` if you pass `a` as the argument to `foo2`. Just because you aren't calling `foo2` on a different object in this example doesn't mean you *couldn't*. – chepner Jul 25 '20 at 16:47
  • @Hans But it doesn't have to be, the second version can be called with different variables. – Barmar Jul 25 '20 at 16:59

1 Answers1

0

In the first, a is a free variable whose value is taken from the nearest enclosing scope (in this case, the scope of foo1) that defines a.

In the second, b is a local variable initialized using the argument passed to foo2 when it is called, which is the variable a defined in foo1.

In each case, you assign -10 to the second "slot" of the same list.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • But both 'a' and 'b' in 'foo2' point to and are merely two names of the same variable, right? – Hans Jul 25 '20 at 16:42
  • Right, though the second `foo2` has the *flexibility* to be called with a different argument. Your first `foo2` is hard-coded to refer to `a` from the enclosing scope. Put another way, the *object* that `foo2`'s free `a` refers to is fixed at the time `foo2` is defined. The object that `foo2`'s local variable `b` refers to is determined when `foo2` is *called*. – chepner Jul 25 '20 at 16:45