[python] 참조로 Python 함수 호출

일부 언어에서는 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 가리키는 .

이것은 서투 르지 않습니다. 작동 방식을 이해하면 아름답고 우아하고 효율적인 시스템입니다.


답변

다음 설명이 잘 요약되기를 바랍니다.

여기서 고려해야 할 두 가지 사항이 있습니다. 변수와 객체입니다.

  1. 변수를 전달하는 경우 값으로 전달됩니다. 즉, 함수 내의 변수에 대한 변경 사항은 해당 함수에 국한되어 있으므로 전역 적으로 반영되지 않습니다. 이것은 ‘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
  1. 목록과 같이 변경 가능한 객체 내에 패킹 된 변수를 전달하는 경우 객체가 다시 할당되지 않는 한 객체에 대한 변경 사항이 전역 적으로 반영됩니다.

예:

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']]
  1. 이제 개체가 다시 할당되는 경우를 고려하십시오. 이 경우 객체는 이것이 발생하는 기능에 로컬 인 새 메모리 위치를 참조하므로 전역 적으로 반영되지 않습니다.

예:

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은 값에 의한 전달도 참조에 의한 전달도 아닙니다. 그것은 더의의 “개체 참조가 값에 의해 전달된다” 와 같이 여기 :

  1. 이것이 가치에 의한 전달이 아닌 이유입니다. 때문에

    def append(list):
        list.append(1)
    
    list = [0]
    reassign(list)
    append(list)
    

값에 의한 전달이 함수가 부모 범위를 전혀 변경하지 못하도록 허용하므로 일종의 참조가 명확하게 전달되었음을 나타내는 [0,1]을 반환 합니다. .

참조에 의한 통과처럼 보입니다, 응? 아니.

  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가 제안하는 것처럼 클래스를 작성하고 해당 클래스 내에서 메서드를 호출해야합니다.