Why can a function modify some arguments as perceived by the caller, but not others?

前端 未结 11 1212
盖世英雄少女心
盖世英雄少女心 2020-11-21 07:10

I\'m trying to understand Python\'s approach to variable scope. In this example, why is f() able to alter the value of x, as perceived within

相关标签:
11条回答
  • 2020-11-21 07:51

    I will rename variables to reduce confusion. n -> nf or nmain. x -> xf or xmain:

    def f(nf, xf):
        nf = 2
        xf.append(4)
        print 'In f():', nf, xf
    
    def main():
        nmain = 1
        xmain = [0,1,2,3]
        print 'Before:', nmain, xmain
        f(nmain, xmain)
        print 'After: ', nmain, xmain
    
    main()
    

    When you call the function f, the Python runtime makes a copy of xmain and assigns it to xf, and similarly assigns a copy of nmain to nf.

    In the case of n, the value that is copied is 1.

    In the case of x the value that is copied is not the literal list [0, 1, 2, 3]. It is a reference to that list. xf and xmain are pointing at the same list, so when you modify xf you are also modifying xmain.

    If, however, you were to write something like:

        xf = ["foo", "bar"]
        xf.append(4)
    

    you would find that xmain has not changed. This is because, in the line xf = ["foo", "bar"] you have change xf to point to a new list. Any changes you make to this new list will have no effects on the list that xmain still points to.

    Hope that helps. :-)

    0 讨论(0)
  • 2020-11-21 07:51

    It´s because a list is a mutable object. You´re not setting x to the value of [0,1,2,3], you´re defining a label to the object [0,1,2,3].

    You should declare your function f() like this:

    def f(n, x=None):
        if x is None:
            x = []
        ...
    
    0 讨论(0)
  • 2020-11-21 08:01

    Some answers contain the word "copy" in a context of a function call. I find it confusing.

    Python doesn't copy objects you pass during a function call ever.

    Function parameters are names. When you call a function Python binds these parameters to whatever objects you pass (via names in a caller scope).

    Objects can be mutable (like lists) or immutable (like integers, strings in Python). Mutable object you can change. You can't change a name, you just can bind it to another object.

    Your example is not about scopes or namespaces, it is about naming and binding and mutability of an object in Python.

    def f(n, x): # these `n`, `x` have nothing to do with `n` and `x` from main()
        n = 2    # put `n` label on `2` balloon
        x.append(4) # call `append` method of whatever object `x` is referring to.
        print('In f():', n, x)
        x = []   # put `x` label on `[]` ballon
        # x = [] has no effect on the original list that is passed into the function
    

    Here are nice pictures on the difference between variables in other languages and names in Python.

    0 讨论(0)
  • 2020-11-21 08:01

    I had modified my answer tons of times and realized i don't have to say anything, python had explained itself already.

    a = 'string'
    a.replace('t', '_')
    print(a)
    >>> 'string'
    
    a = a.replace('t', '_')
    print(a)
    >>> 's_ring'
    
    b = 100
    b + 1
    print(b)
    >>> 100
    
    b = b + 1
    print(b)
    >>> 101
    
    
    def test_id(arg):
        c = id(arg)
        arg = 123
        d = id(arg)
        return
    
    a = 'test ids'
    b = id(a)
    test_id(a)
    e = id(a)
    
    # b = c  = e != d
    
    # this function do change original value
    del change_like_mutable(arg):
        arg.append(1)
        arg.insert(0, 9)
        arg.remove(2)
        return
    
    test_1 = [1, 2, 3]
    change_like_mutable(test_1)
    
    
    
    # this function doesn't 
    def wont_change_like_str(arg):
         arg = [1, 2, 3]
         return
    
    
    test_2 = [1, 1, 1]
    wont_change_like_str(test_2)
    print("Doesn't change like a imutable", test_2)
    
    

    This devil is not the reference / value / mutable or not / instance, name space or variable / list or str, IT IS THE SYNTAX, EQUAL SIGN.

    0 讨论(0)
  • 2020-11-21 08:03

    Python is copy by value of reference. An object occupies a field in memory, and a reference is associated with that object, but itself occupies a field in memory. And name/value is associated with a reference. In python function, it always copy the value of the reference, so in your code, n is copied to be a new name, when you assign that, it has a new space in caller stack. But for the list, the name also got copied, but it refer to the same memory(since you never assign the list a new value). That is a magic in python!

    0 讨论(0)
提交回复
热议问题