일부 언어에서는 ref 또는 val 과 같은 특수 예약어를 사용하여 참조 또는 값으로 매개 변수를 전달할 수 있습니다 . Python 함수에 매개 변수를 전달하면 함수를 떠날 때 매개 변수 값이 변경되지 않습니다.이를 수행하는 유일한 방법은 전역 예약어 를 사용하는 것입니다 (또는 현재 이해하고 있음).
예 1 :
k = 2
def foo (n):
n = n * n #clarity regarding comment below
square = n
return square
j = foo(k)
print j
print k
보여줄 것이다
>>4
>>2
k가 변경되지 않음을 표시
이 예에서 변수 n은 변경되지 않습니다.
예 2 :
n = 0
def foo():
global n
n = n * n
return n
이 예에서는 변수 n이 변경됩니다.
Python에서 함수를 호출 하고 매개 변수 가 전역을 사용하는 대신 값 또는 참조 매개 변수 임을 Python에 알리는 방법 이 있습니까?
둘째, A 레벨 Cambridge 시험에서 이제 함수는 단일 값을 반환하는 반면 프로시 저는 둘 이상의 값을 반환한다고 말합니다 . 80 년대에는 함수에 return 문이 있고 절차에는없는 것을 배웠습니다. 이제 이것이 잘못된 이유는 무엇입니까?
답변
Python의 함수 내에서 str
또는 같은 불변 객체를 변경할 수는 없지만 다음과 같은 tuple
작업을 수행 할 수 있습니다.
def foo(y):
y[0] = y[0]**2
x = [5]
foo(x)
print x[0] # prints 25
그러나 배열의 특정 요소를 항상 제곱 할 필요가없는 한 이상한 방법입니다.
Python에서는 둘 이상의 값을 반환 할 수도 있으므로 참조에 의한 전달의 일부 사용 사례가 덜 중요합니다.
def foo(x, y):
return x**2, y**2
a = 2
b = 3
a, b = foo(a, b) # a == 4; b == 9
이와 같은 값을 반환하면 튜플로 반환되고 차례로 풀립니다.
편집 :
이것에 대해 생각하는 또 다른 방법은 파이썬에서 참조로 변수를 명시 적으로 전달할 수는 없지만 전달 된 객체의 속성을 수정할 수 있다는 것입니다. 제 예 (및 기타)에서는 목록의 구성원을 수정할 수 있습니다. 그러나 전달 된 변수를 완전히 재 할당 할 수는 없습니다. 예를 들어 다음 두 코드는 비슷한 작업을 수행하지만 결과가 다른 것처럼 보입니다.
def clear_a(x):
x = []
def clear_b(x):
while x: x.pop()
z = [1,2,3]
clear_a(z) # z will not be changed
clear_b(z) # z will be emptied
답변
본질적으로 세 종류의 ‘함수 호출’이 있습니다.
- 가치로 전달
- 참조로 전달
- 개체 참조로 전달
Python은 PASS-BY-OBJECT-REFERENCE 프로그래밍 언어입니다.
첫째, 변수와 변수 (객체)의 값은 별개의 것임을 이해하는 것이 중요합니다. 변수는 개체를 ‘가리 킵니다’. 변수는 개체가 아닙니다. 다시:
변수는 객체가 아닙니다
예 : 다음 코드 줄에서 :
>>> x = []
[]
은 빈 목록이고, 빈 목록 x
을 가리키는 변수이지만 x
그 자체는 빈 목록이 아닙니다.
변수 ( x
위의 경우)를 상자로, 변수 ( []
)의 ‘값’을 상자 안의 개체로 간주합니다.
객체 참조로 통과 (파이썬의 경우) :
여기에서 “개체 참조는 값으로 전달됩니다.”
def append_one(li):
li.append(1)
x = [0]
append_one(x)
print x
여기서 문 x = [0]
은 x
객체를 가리키는 변수 (상자)를 만듭니다 [0]
.
호출되는 함수에서 새 상자 li
가 생성됩니다. 의 내용물은 li
상자 내용물과 동일합니다 x
. 두 상자 모두 동일한 개체를 포함합니다. 즉, 두 변수 모두 메모리에서 동일한 객체를 가리 킵니다. 따라서에서 가리키는 객체에 대한 변경 사항은에서 가리키는 객체 li
에도 반영됩니다 x
.
결론적으로, 위 프로그램의 출력은 다음과 같습니다.
[0, 1]
노트 :
변수 li
가 함수에서 재 할당 되면 li
메모리에있는 별도의 개체를 가리 킵니다. x
그러나 이전에 가리키는 메모리의 동일한 개체를 계속 가리 킵니다.
예:
def append_one(li):
li = [0, 1]
x = [0]
append_one(x)
print x
프로그램의 출력은 다음과 같습니다.
[0]
참조로 통과 :
호출 함수의 상자가 호출 된 함수로 전달됩니다. 암시 적으로 상자의 내용 (변수 값)은 호출 된 함수에 전달됩니다. 따라서 호출 된 함수의 상자 내용에 대한 변경 사항은 호출 함수에 반영됩니다.
가치로 통과 :
호출 된 함수에 새 상자가 생성되고 호출 함수 의 상자 내용 사본 이 새 상자에 저장됩니다.
도움이 되었기를 바랍니다.
답변
좋아, 내가 찔러 볼게. 파이썬은 일반적으로 “참조”또는 “값”으로 생각하는 것과는 다른 객체 참조를 통과합니다. 이 예를 보자 :
def foo(x):
print x
bar = 'some value'
foo(bar)
따라서 값이 ‘some value’인 문자열 개체를 만들고라는 변수에 “바인딩”합니다 bar
. C에서는 다음과 유사합니다.bar
‘어떤 값’에 대한 포인터 .
를 호출하면 그 자체로 foo(bar)
전달되지 않습니다 bar
. bar
‘s value :’some value ‘에 대한 포인터를 전달하고 있습니다. 이 시점에서 동일한 문자열 개체에 대한 두 개의 “포인터”가 있습니다.
이제 다음과 비교하십시오.
def foo(x):
x = 'another value'
print x
bar = 'some value'
foo(bar)
여기에 차이점이 있습니다. 라인에서 :
x = 'another value'
실제로의 내용을 변경하지 않습니다 x
. 사실 그것은 불가능합니다. 대신 ‘다른 값’값을 사용하여 새 문자열 개체를 만듭니다. 그 할당 연산자? ” x
새 값으로 가리키는 것을 덮어 쓴다”는 말이 아닙니다 . ” x
대신 새 개체를 가리 키도록 업데이트 “라는 의미입니다. 그 줄 뒤에는 ‘some value'( bar
가리키는)와 ‘another value'(withx
가리키는 .
이것은 서투 르지 않습니다. 작동 방식을 이해하면 아름답고 우아하고 효율적인 시스템입니다.
답변
다음 설명이 잘 요약되기를 바랍니다.
여기서 고려해야 할 두 가지 사항이 있습니다. 변수와 객체입니다.
- 변수를 전달하는 경우 값으로 전달됩니다. 즉, 함수 내의 변수에 대한 변경 사항은 해당 함수에 국한되어 있으므로 전역 적으로 반영되지 않습니다. 이것은 ‘C’와 같은 행동에 가깝습니다.
예:
def changeval( myvar ):
myvar = 20;
print "values inside the function: ", myvar
return
myvar = 10;
changeval( myvar );
print "values outside the function: ", myvar
O / P :
values inside the function: 20
values outside the function: 10
- 목록과 같이 변경 가능한 객체 내에 패킹 된 변수를 전달하는 경우 객체가 다시 할당되지 않는 한 객체에 대한 변경 사항이 전역 적으로 반영됩니다.
예:
def changelist( mylist ):
mylist2=['a'];
mylist.append(mylist2);
print "values inside the function: ", mylist
return
mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist
O / P :
values inside the function: [1, 2, 3, ['a']]
values outside the function: [1, 2, 3, ['a']]
- 이제 개체가 다시 할당되는 경우를 고려하십시오. 이 경우 객체는 이것이 발생하는 기능에 로컬 인 새 메모리 위치를 참조하므로 전역 적으로 반영되지 않습니다.
예:
def changelist( mylist ):
mylist=['a'];
print "values inside the function: ", mylist
return
mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist
O / P :
values inside the function: ['a']
values outside the function: [1, 2, 3]
답변
Python은 값에 의한 전달도 참조에 의한 전달도 아닙니다. 그것은 더의의 “개체 참조가 값에 의해 전달된다” 와 같이 여기 :
-
이것이 가치에 의한 전달이 아닌 이유입니다. 때문에
def append(list): list.append(1) list = [0] reassign(list) append(list)
값에 의한 전달이 함수가 부모 범위를 전혀 변경하지 못하도록 허용하므로 일종의 참조가 명확하게 전달되었음을 나타내는 [0,1]을 반환 합니다. .
참조에 의한 통과처럼 보입니다, 응? 아니.
-
이것이 참조에 의한 통과가 아닌 이유입니다. 때문에
def reassign(list): list = [0, 1] list = [0] reassign(list) print list
목록이 재 할당 될 때 원래 참조가 삭제되었음을 나타내는 [0]을 반환합니다. 참조에 의한 전달은 [0,1]을 반환했을 것입니다. 입니다.
함수가 범위 밖에서 조작하지 않도록하려면 새 개체를 만드는 입력 매개 변수의 복사본을 만들어야합니다.
from copy import copy
def append(list):
list2 = copy(list)
list2.append(1)
print list2
list = [0]
append(list)
print list
답변
기술적으로 파이썬은 값으로 인자를 전달하지 않습니다 : 모두 참조로. 하지만 … 파이썬에는 두 가지 유형의 객체가 있습니다 : 불변 및 변경 가능하므로 다음과 같은 일이 발생합니다.
-
변경 불가능한 인수는 값으로 효과적으로 전달됩니다 . 문자열, 정수, 튜플은 모두 변경 불가능한 객체 유형입니다. 기술적으로는 (모든 매개 변수와 마찬가지로) “참조로 전달”되지만 함수 내에서 제자리에서 변경할 수 없기 때문에 마치 값으로 전달 된 것처럼 보이거나 작동합니다.
-
가변 인수는 효과적으로 참조로 전달됩니다 . 목록 또는 사전은 포인터에 의해 전달됩니다. (append 또는 del)과 같은 함수 내부의 모든 변경 사항은 원래 개체에 영향을줍니다.
이것이 파이썬이 디자인 된 방식입니다. 복사본이없고 모두 참조로 전달됩니다. 복사본을 명시 적으로 전달할 수 있습니다.
def sort(array):
# do sort
return array
data = [1, 2, 3]
sort(data[:]) # here you passed a copy
마지막으로 어떤 함수가 자체 범위를 가지고 있는지 언급하고 싶습니다.
def do_any_stuff_to_these_objects(a, b):
a = a * 2
del b['last_name']
number = 1 # immutable
hashmap = {'first_name' : 'john', 'last_name': 'legend'} # mutable
do_any_stuff_to_these_objects(number, hashmap)
print(number) # 1 , oh it should be 2 ! no a is changed inisde the function scope
print(hashmap) # {'first_name': 'john'}
답변
그래서 이것은 약간 미묘한 요점입니다. 왜냐하면 파이썬은 변수를 값으로 만 전달하지만 파이썬의 모든 변수는 참조이기 때문입니다. 함수 호출로 값을 변경할 수 있도록하려면 변경 가능한 객체가 필요합니다. 예를 들면 :
l = [0]
def set_3(x):
x[0] = 3
set_3(l)
print(l[0])
위의 코드에서 함수는 List 객체 (변경 가능)의 내용을 수정하므로 출력은 0 대신 3입니다.
이 답변은 파이썬에서 ‘값별’이 의미하는 바를 설명하기 위해서만 작성합니다. 위의 코드는 잘못된 스타일이며 값을 변경하려면 MPX가 제안하는 것처럼 클래스를 작성하고 해당 클래스 내에서 메서드를 호출해야합니다.