IT박스

함수가 호출자가 인식 한 일부 인수를 수정할 수 있지만 다른 인수는 수정할 수없는 이유는 무엇입니까?

itboxs 2020. 5. 30. 22:30
반응형

함수가 호출자가 인식 한 일부 인수를 수정할 수 있지만 다른 인수는 수정할 수없는 이유는 무엇입니까?


변수 범위에 대한 Python의 접근 방식을 이해하려고합니다. 이 예에서, 안에 인식 된 것처럼 f()의 값을 변경할 수 있지만 ? 의 값은 변경할 수없는 이유는 무엇입니까?xmain()n

def f(n, x):
    n = 2
    x.append(4)
    print('In f():', n, x)

def main():
    n = 1
    x = [0,1,2,3]
    print('Before:', n, x)
    f(n, x)
    print('After: ', n, x)

main()

산출:

Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After:  1 [0, 1, 2, 3, 4]

일부 답변에는 함수 호출 컨텍스트에서 "복사"라는 단어가 포함되어 있습니다. 혼란 스럽습니다.

파이썬은 복사하지 않습니다 객체 함수 호출을 진행하는 동안 통과를 이제까지 .

기능 매개 변수는 이름 입니다. 함수를 호출하면 파이썬은이 파라미터를 호출 한 객체에 (호출자 범위의 이름을 통해) 바인딩합니다.

객체는 (리스트와 같은) 변경 가능하거나 (파이썬의 정수, 문자열과 같이) 변경할 수 없습니다. 변경할 수있는 가변 객체. 이름을 변경할 수 없으며 다른 객체에 바인딩 할 수 있습니다.

귀하의 예에 대해없는 범위 또는 네임 스페이스 가에 관한 것입니다, 이름 및 바인딩객체의 가변성 파이썬한다.

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

다른 언어의 변수와 파이썬의 이름의 차이점대한 멋진 그림이 있습니다 .


당신은 이미 많은 답변을 얻었으며 JF Sebastian에 널리 동의하지만 이것이 바로 가기로 유용 할 수 있습니다.

을 볼 때마다 함수 범위 내에서 이름 바인딩을 varname =만듭니다 . 이전에 바인드 된 이 범위 내에서 손실 됩니다 .varname

varname.foo()언제든에 메소드를 호출하는 것을 볼 수 있습니다 varname. 이 방법은 varname (예 :)을 변경할 수 있습니다 list.append. varname(또는 오히려 varname이름이 지정된 개체 )가 둘 이상의 범위에 존재할 수 있으며 동일한 개체이므로 모든 범위에서 모든 변경 사항을 볼 수 있습니다.

[ global키워드는 첫 번째 경우에 예외를 만듭니다.]


f실제로 값을 변경하지는 않습니다 x(항상 목록의 인스턴스에 대한 참조와 동일 함). 오히려이 목록 내용변경합니다 .

두 경우 모두 참조 사본 이 함수에 전달됩니다. 함수 안에서

  • n새로운 가치가 부여됩니다. 함수 내부의 참조 만이 아니라 함수 내부의 참조 만 수정됩니다.
  • x새로운 값이 할당되지 않습니다 : 함수 내부와 외부의 참조는 수정되지 않습니다. 대신 x 이 수정되었습니다.

모두 이후 x함수 안쪽과 바깥 쪽은 동일한 값을 참조 두 변형 참조. 반대로 n함수 내부와 외부 는 함수 내부에서 재 할당 된 다른 값을 n나타냅니다.


혼란을 줄이기 위해 변수 이름을 바꿀 것입니다. n- > nf 또는 nmain . x- > xf 또는 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()

당신이 함수를 호출 할 때 F를 , 파이썬 런타임의 사본을 만들어 xmain 과 양수인을 XF , 유사의 사본 할당 nmain을NF .

n 의 경우 복사되는 값은 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. :-)


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 = []
    ...

n is an int (immutable), and a copy is passed to the function, so in the function you are changing the copy.

X is a list (mutable), and a copy of the pointer is passed o the function so x.append(4) changes the contents of the list. However, you you said x = [0,1,2,3,4] in your function, you would not change the contents of x in main().


If the functions are re-written with completely different variables and we call id on them, it then illustrates the point well. I didn't get this at first and read jfs' post with the great explanation, so I tried to understand/convince myself:

def f(y, z):
    y = 2
    z.append(4)
    print ('In f():             ', id(y), id(z))

def main():
    n = 1
    x = [0,1,2,3]
    print ('Before in main:', n, x,id(n),id(x))
    f(n, x)
    print ('After in main:', n, x,id(n),id(x))

main()
Before in main: 1 [0, 1, 2, 3]   94635800628352 139808499830024
In f():                          94635800628384 139808499830024
After in main: 1 [0, 1, 2, 3, 4] 94635800628352 139808499830024

z and x have the same id. Just different tags for the same underlying structure as the article says.


Python is a pure pass-by-value language if you think about it the right way. A python variable stores the location of an object in memory. The Python variable does not store the object itself. When you pass a variable to a function, you are passing a copy of the address of the object being pointed to by the variable.

Contrasst these two functions

def foo(x):
    x[0] = 5

def goo(x):
    x = []

Now, when you type into the shell

>>> cow = [3,4,5]
>>> foo(cow)
>>> cow
[5,4,5]

Compare this to goo.

>>> cow = [3,4,5]
>>> goo(cow)
>>> goo
[3,4,5]

In the first case, we pass a copy the address of cow to foo and foo modified the state of the object residing there. The object gets modified.

In the second case you pass a copy of the address of cow to goo. Then goo proceeds to change that copy. Effect: none.

I call this the pink house principle. If you make a copy of your address and tell a painter to paint the house at that address pink, you will wind up with a pink house. If you give the painter a copy of your address and tell him to change it to a new address, the address of your house does not change.

The explanation eliminates a lot of confusion. Python passes the addresses variables store by value.


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!


My general understanding is that any object variable (such as a list or a dict, among others) can be modified through its functions. What I believe you are not able to do is reassign the parameter - i.e., assign it by reference within a callable function.

That is consistent with many other languages.

Run the following short script to see how it works:

def func1(x, l1):
    x = 5
    l1.append("nonsense")

y = 10
list1 = ["meaning"]
func1(y, list1)
print(y)
print(list1)

참고URL : https://stackoverflow.com/questions/575196/why-can-a-function-modify-some-arguments-as-perceived-by-the-caller-but-not-oth

반응형