함수가 호출자가 인식 한 일부 인수를 수정할 수 있지만 다른 인수는 수정할 수없는 이유는 무엇입니까?
변수 범위에 대한 Python의 접근 방식을 이해하려고합니다. 이 예에서, 안에 인식 된 것처럼 f()
의 값을 변경할 수 있지만 ? 의 값은 변경할 수없는 이유는 무엇입니까?x
main()
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)
'IT박스' 카테고리의 다른 글
실과 섬유의 차이점은 무엇입니까? (0) | 2020.05.31 |
---|---|
SSL이 부과하는 오버 헤드는 얼마입니까? (0) | 2020.05.30 |
C #에서 참조 유형 변수에 "ref"를 사용하는 것은 무엇입니까? (0) | 2020.05.30 |
대문자 또는 소문자 doctype? (0) | 2020.05.30 |
언제, 왜 사전 대신 명명 된 튜플을 사용해야합니까? (0) | 2020.05.30 |