참조로 변수를 전달하는 방법은 무엇입니까?


2628

파이썬 문서는 매개 변수가 참조 또는 값으로 전달되는지에 대해 명확하지 않은 것으로 보이며 다음 코드는 변경되지 않은 값 'Original'을 생성합니다.

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

실제 참조로 변수를 전달하기 위해 할 수있는 일이 있습니까?


23
간단한 설명 / 설명은 이 stackoverflow 질문에 대한 첫 번째 답변을 참조하십시오 . 문자열은 변경할 수 없으므로 변경되지 않으며 새 변수가 만들어 지므로 "외부"변수는 ​​여전히 동일한 값을 갖습니다.
PhilS 2016 년

10
BlairConrad의 답변 코드는 훌륭하지만 DavidCournapeau와 DarenThomas가 제공 한 설명은 정확합니다.
Ethan Furman

70
선택한 답변을 읽기 전에이 짧은 텍스트를 읽으십시오. 다른 언어에는 "변수"가 있고 Python에는 "names"가 있습니다. "변수"와 "참조"대신 "이름"과 "객체"를 생각하면 많은 유사한 문제를 피해야합니다.
lqc

24
이것이 왜 불필요하게 클래스를 사용합니까? 이것은 Java가 아닙니다 : P
Peter R

2
또 다른 해결 방법은 다음과 같이 래퍼 '참조'를 만드는 것입니다. ref = type ( '', (), { 'n': 1}) stackoverflow.com/a/1123054/409638
robert

답변:


2830

인수는 할당에 의해 전달됩니다 . 이것의 근거는 두 가지입니다.

  1. 전달 된 파라미터는 사실이다 기준 개체에 (그러나, 기준이되는 값으로 전달)
  2. 일부 데이터 유형은 변경 가능하지만 다른 유형은 변경 불가능

그래서:

  • 당신이 전달하는 경우 변경 가능한 방법으로 개체를, 방법은 같은 객체에 대한 참조를 가져옵니다 당신은 당신의 마음의 기쁨으로 변이 할 수 있지만,이 방법에 대한 참조를 바인딩하는 경우, 외부 범위는 후에 그것에 대해 아무것도 몰라, 것 완료되었으므로 외부 참조는 여전히 원래 객체를 가리 킵니다.

  • 당신이 전달하는 경우 불변 하는 방법에 오브젝트를, 당신은 여전히 외부 참조를 바인딩 할 수없고 심지어 개체를 변이 수 없습니다.

더 명확하게하기 위해 몇 가지 예를 들어 보겠습니다.

리스트-가변 타입

메소드에 전달 된 목록을 수정 해 봅시다 :

def try_to_change_list_contents(the_list):
    print('got', the_list)
    the_list.append('four')
    print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

산출:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

전달 된 매개 변수 outer_list는 복사본이 아닌에 대한 참조 이므로 변경 목록 메소드를 사용하여 변경하고 외부 범위에 변경 사항을 반영 할 수 있습니다.

이제 매개 변수로 전달 된 참조를 변경하려고 할 때 어떤 일이 발생하는지 봅시다 :

def try_to_change_list_reference(the_list):
    print('got', the_list)
    the_list = ['and', 'we', 'can', 'not', 'lie']
    print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

산출:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

때문에 the_list매개 변수가 그것에 새 목록을 할당 값에 의해 전달 된 방법 이외의 코드를 볼 수 있다는 아무런 영향을 미치지 않습니다. 는 the_list의 복사본이었다 outer_list참조, 우리는 한 the_list새 목록에 지점을하지만, 변경할 수있는 방법이 없었다 outer_list뾰족한는.

문자열-불변의 타입

불변이므로 문자열의 내용을 변경하기 위해 할 수있는 일은 없습니다

이제 참조를 변경해 봅시다

def try_to_change_string_reference(the_string):
    print('got', the_string)
    the_string = 'In a kingdom by the sea'
    print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

산출:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

다시 말하지만 the_string매개 변수가 값으로 전달되었으므로 새 문자열을 할당하면 메서드 외부의 코드에서 볼 수 없었습니다. 는 the_string의 복사본이었다 outer_string참조, 우리는 한 the_string새로운 문자열로 포인트를하지만, 변경할 수있는 방법이 없었다 outer_string뾰족한는.

나는 이것이 약간의 정리를 바랍니다.

편집 : 이것은 @David가 처음에 "실제 참조로 변수를 전달하기 위해 할 수있는 일이 있습니까?"라는 질문에 대답하지는 않습니다. 그 작업을 해보자.

우리는 어떻게이 문제를 해결합니까?

@Andrea의 답변에서 알 수 있듯이 새로운 값을 반환 할 수 있습니다. 이것은 물건이 전달되는 방식을 바꾸지는 않지만 원하는 정보를 다시 얻을 수있게합니다.

def return_a_whole_new_string(the_string):
    new_string = something_to_do_with_the_old_string(the_string)
    return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

반환 값을 사용하지 않으려면 값을 보유하고 함수에 전달하거나 목록과 같은 기존 클래스를 사용하는 클래스를 만들 수 있습니다.

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
    new_string = something_to_do_with_the_old_string(stuff_to_change[0])
    stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

비록 약간 성가신 것 같습니다.


165
"참조로"를 전달하면 실제로 참조 로 값을 전달 하는 것입니다. "참조로"정의 : P
Andrea Ambu

104
귀하의 조건을 이해하지 못했습니다. 나는 한동안 C 게임에서 벗어 났지만 다시 돌아 왔을 때 "참조로 전달"이 없었습니다. 물건을 전달할 수 있었고 항상 값으로 전달되었으므로 매개 변수 목록에있는 모든 것이 복사되었습니다. 그러나 때때로 문제는 메모리 조각 (기본, 배열, 구조체 등)을 따라갈 수있는 포인터 였지만 함수를 다했을 때 외부 범위에서 복사 된 포인터를 변경할 수 없었습니다. 원래 포인터는 여전히 동일한 주소를 가리 켰습니다. C ++에서는 다르게 동작하는 참조를 도입했습니다.
블레어 콘래드

34
@ Zac Bowling 나는 당신이 말하는 것이 실제적인 의미 에서이 답변과 어떻게 관련이 있는지 실제로 알지 못합니다. 파이썬 초보자는 지나가는에 대해 알고 싶다면 REF / 발,이 대답에서 테이크 아웃은 다음과 같습니다 1 당신은 수있는 한, 변수의 '외부'의 값을 수정, 함수는 인수로 수신하는 참조를 사용 새 객체를 참조하도록 매개 변수를 다시 할당하지 않기 때문입니다. 2- 불변 유형에 할당하면 항상 새 객체가 생성되어 외부 변수에 대한 참조가 손상됩니다.
Cam Jackson

11
@CamJackson, 더 나은 예제가 필요합니다-숫자는 파이썬에서 변경할 수없는 객체입니다. 게다가, 말할 아닐 수 있는 등호의 왼쪽에 첨자없이 할당이 불변인지 여부를 새로운 객체에 이름을 할당 할 것인가? def Foo(alist): alist = [1,2,3]없는 발신자의 관점에서 목록의 내용을 수정합니다.
Mark Ransom

59
-1. 표시된 코드는 훌륭합니다. 완전히 잘못된 방법에 대한 설명입니다. 이유에 대한 올바른 설명은 DavidCournapeau 또는 DarenThomas의 답변을 참조하십시오.
Ethan Furman

685

파이썬에서 변수가 무엇인지에 대한 오해에서 문제가 발생합니다. 대부분의 전통적인 언어에 익숙하다면 다음 순서로 일어나는 일에 대한 정신적 모델이 있습니다.

a = 1
a = 2

a그 값을 저장하는 메모리 위치 라고 생각 하고 값 1을 저장하도록 업데이트됩니다 2. 그것이 파이썬에서 일하는 방식이 아닙니다. 오히려 a값이있는 객체에 대한 참조로 1시작한 다음 값 이있는 객체에 대한 참조로 다시 할당됩니다 2. 이 두 개체는 a더 이상 첫 번째 개체를 참조하지 않더라도 계속 공존 할 수 있습니다 . 실제로 그것들은 프로그램 내에서 다른 많은 참조에 의해 공유 될 수 있습니다.

매개 변수를 사용하여 함수를 호출하면 전달 된 객체를 참조하는 새 참조가 작성됩니다. 이는 함수 호출에 사용 된 참조와 별개이므로 해당 참조를 업데이트하여 참조를 참조 할 수있는 방법이 없습니다. 새로운 객체. 귀하의 예에서 :

def __init__(self):
    self.variable = 'Original'
    self.Change(self.variable)

def Change(self, var):
    var = 'Changed'

self.variable문자열 객체에 대한 참조 'Original'입니다. 호출 Change하면 var객체에 대한 두 번째 참조 를 만듭니다. 함수 내에서 var다른 문자열 객체에 대한 참조 를 다시 할당 'Changed'하지만 참조 self.variable는 분리되어 있으며 변경되지 않습니다.

이를 해결하는 유일한 방법은 변경 가능한 객체를 전달하는 것입니다. 두 참조 모두 동일한 객체를 참조하므로 객체에 대한 모든 변경 사항이 두 곳에 모두 반영됩니다.

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

def Change(self, var):
    var[0] = 'Changed'

106
간결한 설명. "함수를 호출 할 때 ..."라는 단락은 'Python 함수 매개 변수는 참조이며 값에 의해 전달됩니다'라는 다소 비밀스러운 문구에 대해 들어 본 최고의 설명 중 하나입니다. 나는 당신이 그 단락 만 이해한다면, 다른 모든 것들은 단지 의미가 있고 거기에서 논리적 결론으로 ​​흐릅니다. 그런 다음 새 객체를 생성 할 때와 기존 객체를 수정할 때 알아야합니다.
캠 잭슨

3
그러나 어떻게 참조를 재 할당 할 수 있습니까? 'var'의 주소를 변경할 수 없다고 생각했지만 문자열 'Changed'가 이제 'var'메모리 주소에 저장 될 것입니다. 귀하의 설명은 "변경됨"과 "원본"이 메모리의 다른 위치에 속하는 것처럼 보이고 'var'을 다른 주소로 전환하기 만하면됩니다. 그 맞습니까?
Glassjawed

9
@Glassjawed, 나는 당신이 그것을 얻고 있다고 생각합니다. "Changed"와 "Original"은 서로 다른 메모리 주소에있는 두 개의 서로 다른 문자열 객체이며 'var'은 하나를 가리키는 것에서 다른 것을 가리키는 것입니다.
마크 랜섬

id () 함수를 사용하면 문제를 명확히하는 데 도움이됩니다. 파이썬이 새 객체를 만들 때 명확하게하기 때문입니다 (그래도 어쨌든 생각합니다).
Tim Richardson

1
가장 간단한 용어로 @MinhTran은 객체를 "참조"하는 것입니다. 그것의 물리적 표현은 아마도 포인터 일 것입니다. 그러나 그것은 단순히 구현 세부 사항입니다. 그것은 실제로 추상적 인 개념입니다.
Mark Ransom

329

다른 답변은 다소 길고 복잡하다는 것을 알았 으므로이 간단한 다이어그램을 작성하여 Python이 변수 및 매개 변수를 처리하는 방식을 설명했습니다. 여기에 이미지 설명을 입력하십시오


2
사랑스럽고 캐주얼 한 구경꾼에게는 분명하지 않은 중간 과제가 있다는 미묘한 차이를 쉽게 발견 할 수 있습니다. +1
22866

9
A가 변경 가능한지 여부는 중요하지 않습니다. B와 다른 것을 할당 해도 A는 바뀌지 않습니다 . 객체가 변경 가능한 경우 반드시 변경할 수 있습니다. 그러나 그것은 이름에 직접 할당하는 것과는 아무 상관이 없습니다 ..
Martijn Pieters

1
@Martijn 당신이 맞아요. 나는 가변성을 언급하는 대답의 일부를 제거했습니다. 나는 그것이 더 간단해질 수 있다고 생각하지 않습니다.
Zenadix

4
업데이트 해 주셔서 감사합니다. 훨씬 좋습니다! 대부분의 사람들에게 혼란을주는 것은 구독에 할당하는 것입니다. 예를 들어 B[0] = 2, 직접 할당 대, B = 2.
Martijn Pieters

11
"A는 B에 할당됩니다." 모호하지 않습니까? 나도 의미 할 수있는 일반 영어로 생각 A=B하거나 B=A.
하트셉수트

240

값으로 전달 또는 참조로 전달되지 않으며 개체 별 호출입니다. Fredrik Lundh의 이것을보십시오 :

http://effbot.org/zone/call-by-object.htm

중요한 인용문은 다음과 같습니다.

"... 변수 [이름]은 객체 가 아닙니다 . 다른 변수로 표시하거나 객체가 참조 할 수 없습니다."

예를 들어, Change메소드가 호출되면 네임 스페이스 가 작성됩니다. 및 var문자열 객체에 대해, 해당 네임 스페이스 내에서 이름이됩니다 'Original'. 그런 다음 해당 개체는 두 개의 네임 스페이스에 이름을 갖습니다. 그런 다음 새 문자열 객체에 var = 'Changed'바인딩 var하므로 메서드의 네임 스페이스가 잊어 버립니다 'Original'. 마지막으로, 그 네임 스페이스는 잊혀지고 문자열도 'Changed'함께 잊어 버립니다 .


21
나는 그것을 사는 것이 어렵다는 것을 안다. 나에게 Java와 마찬가지로 매개 변수는 메모리의 객체에 대한 포인터이며 해당 포인터는 스택 또는 레지스터를 통해 전달됩니다.
Luciano

10
이것은 자바와 다릅니다. 동일하지 않은 경우 중 하나는 불변 개체입니다. 사소한 함수 람다 x : x에 대해 생각해보십시오. x = [1, 2, 3] 및 x = (1, 2, 3)에 적용하십시오. 첫 번째 경우, 반환 된 값은 입력의 사본이며 두 번째 경우와 동일합니다.
David Cournapeau

26
아니요, 객체에 대한 Java의 의미와 정확히 같습니다. "첫 번째 경우 반환 된 값은 입력의 사본이며 두 번째 경우는 동일합니다."라는 의미가 무엇인지 잘 모르겠습니다. 그러나 그 진술은 분명히 틀린 것 같습니다.
Mike Graham

23
Java와 정확히 동일합니다. 객체 참조는 값으로 전달됩니다. 다르게 생각하는 사람은 다음 swap과 같이 두 개의 참조를 교환 할 수 있는 함수에 Python 코드를 첨부해야 합니다. a = [42] ; b = 'Hello'; swap(a, b) # Now a is 'Hello', b is [42]
cayhorstmann

24
Java로 객체를 전달할 때 Java와 정확히 동일합니다. 그러나 Java에는 또한 기본 요소의 값을 복사하여 전달되는 기본 요소가 있습니다. 따라서이 경우에는 다릅니다.
Claudiu

174

참조 / 가치 대신 할당 으로 전달 되는 것을 생각하십시오 . 그렇게하면 정규 과제 동안 어떤 일이 발생하는지 이해하는 한 항상 명확합니다.

따라서리스트를 함수 / 메소드에 전달할 때리스트는 매개 변수 이름에 할당됩니다. 목록에 추가하면 목록이 수정됩니다. 함수 에서 목록을 다시 할당하면 다음과 같은 이유로 원래 목록이 변경되지 않습니다.

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

불변 유형은 수정할 수 없으므로 값으로 전달되는 것처럼 보입니다 . int를 함수에 전달하면 int를 함수의 매개 변수에 할당하는 것을 의미합니다. 다시 할당 할 수는 있지만 원래 변수 값은 변경되지 않습니다.


3
언뜻보기 에이 답변은 원래 질문을 회피하는 것 같습니다. 두 번째로 읽은 후에는 이것이 문제를 매우 명확하게한다는 것을 깨달았습니다. 이 "이름 할당"개념에 대한 후속 조치는 여기에서 찾을 수 있습니다. Pythonista와 같은 코드 : 관용적 파이썬
Christian Groleau

65

Effbot (일명 Fredrik Lundh)은 Python의 변수 전달 스타일을 객체 별 호출로 설명했습니다. http://effbot.org/zone/call-by-object.htm

객체는 힙에 할당되며 포인터는 어디에서나 전달 될 수 있습니다.

  • 과 같은 할당을 수행 x = 1000하면 현재 네임 스페이스의 "x"문자열을 1000을 포함하는 정수 객체에 대한 포인터에 매핑하는 사전 항목이 생성됩니다.

  • 로 "x"를 업데이트 x = 2000하면 새 정수 객체가 만들어지고 새 객체를 가리 키도록 사전이 업데이트됩니다. 오래 된 천 개체는 변경되지 않습니다 (그리고 다른 것이 개체를 참조하는지 여부에 따라 살아 있거나 없을 수 있습니다).

  • 와 같은 새 할당을 수행하면 y = x"x"에 대한 항목과 동일한 객체를 가리키는 새 사전 항목 "y"가 생성됩니다.

  • 문자열 및 정수와 같은 객체는 변경할 수 없습니다 . 이것은 객체가 생성 된 후에 객체를 변경할 수있는 메소드가 없음을 의미합니다. 예를 들어, 정수 객체가 천 번 생성되면 절대 변경되지 않습니다. 수학은 새로운 정수 객체를 생성하여 수행됩니다.

  • 리스트와 같은 객체는 변경 가능 합니다. 이것은 객체의 내용이 객체를 가리키는 것으로 변경 될 수 있음을 의미합니다. 예를 들어 x = []; y = x; x.append(10); print y인쇄 [10]합니다. 빈 목록이 작성되었습니다. "x"와 "y"는 모두 동일한 목록을 가리 킵니다. APPEND의 방법 (데이터베이스에 레코드를 추가하는 등의) 변이 (업데이트) 목록 객체와 결과가 모두 "X"와 "Y"를 볼 수는 (단지 데이터베이스 업데이트로 해당 데이터베이스에 대한 모든 연결을 볼 것).

그것이 당신을 위해 문제를 분명히하기를 바랍니다.


2
나는 개발자로부터 이것에 대해 배우는 것에 정말로 감사합니다. id()pepr의 답변에서 알 수 있듯이 함수가 포인터 (객체 참조) 값을 반환하는 것이 사실 입니까?
정직한 아베

4
@HonestAbe 예, CPython에서 id () 는 주소를 반환합니다. 그러나 PyPy 및 Jython과 같은 다른 파이썬에서 id () 는 고유 한 객체 식별자입니다.
Raymond Hettinger

59

기술적으로 파이썬은 항상 pass by reference values를 사용합니다 . 본인의 진술을 뒷받침하기 위해 다른 답변 을 반복하겠습니다 .

파이썬은 항상 참조로 전달 값을 사용합니다. 예외는 없습니다. 모든 변수 할당은 참조 값을 복사하는 것을 의미합니다. 예외 없음. 모든 변수는 참조 값에 바인딩 된 이름입니다. 항상.

참조 값을 대상 개체의 주소로 생각할 수 있습니다. 주소는 사용될 때 자동으로 역 참조됩니다. 이런 식으로 참조 값으로 작업하면 대상 객체로 직접 작업하는 것처럼 보입니다. 그러나 목표를 향해 한 걸음 더 나아가는 것 사이에는 항상 참조가 있습니다.

다음은 파이썬이 참조로 전달을 사용한다는 것을 증명하는 예입니다.

인수 전달의 예를 보여줍니다.

인수가 값으로 전달되면 외부를 lst수정할 수 없습니다. 녹색은 대상 객체이며 (검정은 내부에 저장된 값, 빨간색은 객체 유형), 노란색은 참조 값이 내부에있는 메모리이며 화살표로 표시됩니다. 파란색 실선 화살표는 점선 파선 화살표 경로를 통해 함수에 전달 된 참조 값입니다. 못생긴 짙은 노란색은 내부 사전입니다. (실제로 녹색 타원으로 그릴 수도 있습니다. 색상과 모양은 내부라고 말합니다.)

id()내장 함수를 사용하여 참조 값이 무엇인지 (즉, 대상 객체의 주소)를 알 수 있습니다.

컴파일 된 언어에서 변수는 유형의 값을 캡처 할 수있는 메모리 공간입니다. Python에서 변수는 대상 객체에 대한 참조 값을 보유하는 참조 변수에 바인딩 된 이름 (내부적으로 문자열로 캡처 됨)입니다. 변수의 이름은 내부 사전의 키이며 해당 사전 항목의 값 부분은 참조 값을 대상에 저장합니다.

파이썬에서는 참조 값이 숨겨져 있습니다. 참조 값을 저장하기위한 명시적인 사용자 유형이 없습니다. 그러나 모든 컨테이너가 요소를 대상 객체에 대한 참조로도 저장하기 때문에 목록 요소 (또는 다른 적합한 컨테이너 유형의 요소)를 참조 변수로 사용할 수 있습니다. 즉, 요소는 실제로 컨테이너 안에 포함되지 않으며 요소에 대한 참조 만 있습니다.


1
실제로 이것은 참조 값으로 통과가 확인됩니다. 예제가 좋지는 않았지만이 답변에 +1했습니다.
BugShotGG

30
새로운 용어 (예 : "기준 값으로 전달"또는 "객체 별 호출")는 발명되지 않습니다. "(값 | 참조 | 이름)으로 전화"는 표준 용어입니다. "참조"는 표준 용어입니다. 값으로 참조를 전달하면 표준 용어를 사용하여 Python, Java 및 기타 여러 언어의 동작을 정확하게 설명합니다.
cayhorstmann

4
@cayhorstmann : 문제는 파이썬 변수 가 다른 언어에서와 같은 용어 의미를 갖지 않는다는 것입니다. 이런 식 으로 참조에 의한 호출은 여기에 적합하지 않습니다. 또한 용어 참조정확히 어떻게 정의 합니까? 비공식적으로 파이썬 방식은 객체의 주소를 전달하는 것으로 쉽게 설명 할 수 있습니다. 그러나 잠재적으로 분산 된 Python 구현에는 맞지 않습니다.
pepr

1
나는이 대답을 좋아하지만 예제가 실제로 흐름을 돕는 지 또는 아프게하는지 고려할 수 있습니다. 또한 'reference value'를 'object reference'로 바꾸면 다음과 같이 '공식'으로 간주 할 수있는 용어를 사용하게됩니다. 함수 정의
정직한 Abe

2
인용문 끝에는 각주가 있습니다. "실제로 객체 참조에 의한 호출 은 더 나은 설명이 될 것입니다. 변경 가능한 객체가 전달되면 호출자는 수신자가 변경 한 내용을 볼 수 있기 때문에 ... " 다른 언어로 작성된 용어를 맞추려고하면 혼동이 발생한다는 데 동의합니다. 의미론을 제외하고는 사전 / 이름 공간, 이름 바인딩 작업 및 이름 → 포인터 → 객체의 관계 (이미 알고 있음)를 이해해야 합니다.
정직한 Abe

56

파이썬에는 변수가 없습니다

매개 변수 전달을 이해하는 열쇠는 "변수"에 대한 생각을 멈추는 것입니다. 파이썬에는 이름과 객체가 있으며 함께 변수처럼 보이지만 항상 세 가지를 구별하는 것이 유용합니다.

  1. 파이썬에는 이름과 객체가 있습니다.
  2. 할당은 이름을 객체에 바인딩합니다.
  3. 함수에 인수를 전달하면 이름 (함수의 매개 변수 이름)도 객체에 바인딩됩니다.

그것이 전부입니다. 돌연변이는이 질문과 관련이 없습니다.

예:

a = 1

이것은 이름 a을 값 1을 보유한 정수 유형의 오브젝트에 바인드합니다 .

b = x

이 이름 바인딩 b이름이 것과 같은 객체에 x현재에 바인딩됩니다. 나중에 이름 bx더 이상 이름과 관련이 없습니다.

Python 3 언어 참조의 3.14.2 단원을 참조하십시오 .

질문에서 예를 읽는 방법

질문에 표시된 코드 self.Change(self.variable)에서이 명령문 은 이름 var(함수 범위 Change)을 값을 보유하는 객체 에 바인딩하고 'Original'할당 var = 'Changed'(함수 본문 Change)은 동일한 이름을 다시 지정합니다. 문자열을 잡아야하지만 완전히 다른 것이 될 수 있습니다).

참조로 전달하는 방법

따라서 변경하려는 것이 변경 가능한 객체이면 모든 것이 효과적으로 참조로 전달되므로 문제가 없습니다.

그것이 경우 불변의 객체 (예를 들어, 부울, 숫자, 문자열), 이동하는 방법은 변경 가능한 객체를 래핑하는 것입니다.
이것에 대한 빠르고 더러운 솔루션은 하나의 요소 목록입니다 ( self.variablepass 대신 [self.variable]함수 modify var[0]).
pythonic 접근법은 사소한 하나의 속성 클래스를 도입하는 것입니다. 이 함수는 클래스의 인스턴스를 수신하고 속성을 조작합니다.


20
"Python에는 변수가 없습니다"는 어리 석고 혼란스러운 슬로건이며, 사람들이 그 말을 멈출 수 있기를 바랍니다 ... :(이 답변의 나머지 부분이 좋습니다!
Ned Batchelder

9
충격적 일 수 있지만 어리석지 않습니다. 그리고 나는 그것이 혼란스럽지 않다고 생각한다. 그것은 다가오는 설명에 대해 수령인의 마음을 열어주고 그녀에게 유용한 "변수 대신 무엇을 가지고 있는지 궁금하다"라는 태도를 갖게한다. (예, 귀하의 마일리지가 다를 수 있습니다.)
루츠 Prechelt에게

13
Javascript에 변수가 없다고 말 하시겠습니까? 그들은 파이썬과 동일하게 작동합니다. 또한 Java, Ruby, PHP 등 .... 더 나은 교수법은 "Python의 변수는 C와 다르게 작동합니다."라고 생각합니다.
Ned Batchelder

9
예, Java에는 변수가 있습니다. 파이썬과 자바 스크립트, 루비, PHP 등도 마찬가지입니다. 자바 int에서는 변수 를 선언 하지는 않지만 말할 수 Integer는 없습니다. 둘 다 변수를 선언합니다. Integer변수, 목적 int변수 프리미티브이다. 예를 들어,을 표시하여 변수 작동 방식을 보여주었습니다 a = 1; b = a; a++ # doesn't modify b. 파이썬에서도 마찬가지입니다 (파이썬 += 1에는 없기 때문에 사용 ++)!
Ned Batchelder

1
"변수"의 개념은 복잡하고 종종 모호합니다. 변수는 이름으로 식별되는 값의 컨테이너입니다. 파이썬에서 값은 객체이고 컨테이너는 객체입니다 (문제를 보시겠습니까?) 그리고 이름은 실제로 별개의 것입니다. 이런 식으로 변수를 정확하게 이해 하는 것이 훨씬 어렵다고 생각합니다 . 이름과 객체 설명은 더 어려워 보이지만 실제로는 더 단순합니다.
Lutz Prechelt

43

내가 일반적으로 사용하는 간단한 트릭은 목록으로 감싸는 것입니다.

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(예, 이것이 불편할 수 있음을 알고 있지만 때로는 그렇게하기에 충분히 간단합니다.)


7
소량의 텍스트에 +1하여 파이썬이 참조로 전달하지 않는 문제에 대한 필수 해결 방법을 제공합니다. (이 페이지의 어느 곳이나 여기에 맞는 후속 의견 / 질문으로 : 파이썬이 C #처럼 "ref"키워드를 제공 할 수없는 이유는 분명하지 않습니다. 이것은 함수 내의 인수에 대한 참조를 목록의 0 번째 요소로 취급합니다.)
M Katz

5
좋은. 심판에게 전달하려면 []로 감싸십시오.
Justas

38

(편집-블레어는 그의 정확한 답변을 업데이트하여 이제는 정확 해졌습니다)

블레어 콘래드 (Blair Conrad)에 의해 가장 많은 표를 얻은 현재 게시물은 그 결과와 관련하여 정확하지만 오해의 소지가 있으며 그 정의에 따라 경계선이 잘못되었다는 점에 주목해야합니다. 사용자가 참조로 전달하거나 값으로 전달할 수있는 많은 언어 (C와 같은)가 있지만 Python은 그중 하나가 아닙니다.

David Cournapeau의 답변은 실제 답변을 가리키며 Blair Conrad의 게시물의 동작이 왜 정확하지 않은지 설명합니다.

파이썬이 값으로 전달되는 한, 일부 데이터 ( "값"또는 "참조")가 전송되어야하기 때문에 모든 언어는 값으로 전달됩니다. 그러나 이것이 C 프로그래머가 그것을 생각한다는 의미에서 파이썬이 가치를 지니고 있다는 것을 의미하지는 않습니다.

당신이 행동을 원한다면 Blair Conrad의 대답은 괜찮습니다. 그러나 파이썬이 가치를 지니지 않거나 참조로 전달되지 않는 이유의 요점을 알고 싶다면 David Cournapeau의 대답을 읽으십시오.


4
모든 언어가 가치에 의해 호출되는 것은 사실이 아닙니다. C ++ 또는 파스칼 (그리고 내가 모르는 다른 많은 것)에서는 참조로 전화했습니다. 예를 들어, C ++에서는 void swap(int& x, int& y) { int temp = x; x = y; y = temp; }전달 된 변수를 교체합니다. 파스칼에서는을 var대신 사용 합니다 &.
cayhorstmann

2
나는 이것에 대해 오랫동안 대답했다고 생각했지만 그것을 보지 못했습니다. 완전성을 위해-cayhorstmann은 내 대답을 오해했습니다. 나는 대부분의 사람들이 C / C ++에 관해 처음 배우는 용어로 모든 것이 가치 의해 요구 된다고 말하지 않았다 . 단순히 일부 값이 전달되고 (값, 이름, 포인터 등) Blair의 원래 답변에 사용 된 용어가 정확하지 않은 것입니다.
KobeJohn

24

여기에 정말 좋은 답변이 있습니다.

x = [ 2, 4, 4, 5, 5 ]
print x  # 2, 4, 4, 5, 5

def go( li ) :
  li = [ 5, 6, 7, 8 ]  # re-assigning what li POINTS TO, does not
  # change the value of the ORIGINAL variable x

go( x ) 
print x  # 2, 4, 4, 5, 5  [ STILL! ]


raw_input( 'press any key to continue' )

2
그러나 x = [2, 4, 4, 5, 5], y = x, X [0] = 1이면 x x [1, 4, 4, 5, 5] print y # [1 , 4, 4, 5, 5]
laycat 2018 년

19

이 경우 var메서드에서 제목 Change이 지정된 변수 에에 대한 참조가 할당 self.variable되고 즉시 문자열을에 할당합니다 var. 더 이상 가리 키지 않습니다 self.variable. 다음 코드 스 니펫은 varand가 가리키는 데이터 구조 ( self.variable이 경우 목록) 를 수정하면 어떻게되는지 보여줍니다 .

>>> class PassByReference:
...     def __init__(self):
...         self.variable = ['Original']
...         self.change(self.variable)
...         print self.variable
...         
...     def change(self, var):
...         var.append('Changed')
... 
>>> q = PassByReference()
['Original', 'Changed']
>>> 

다른 사람이 이것을 더 명확히 할 수 있다고 확신합니다.


18

파이썬의 할당 별 체계는 C ++의 참조 매개 변수 옵션과 완전히 동일하지 않지만 실제로는 C 언어 (및 기타)의 인수 전달 모델과 매우 유사합니다.

  • 불변 인수는 효과적으로 " 가치 별 " 으로 전달 됩니다 . 정수 및 문자열과 같은 객체는 복사하는 대신 객체 참조로 전달되지만 변경 불가능한 객체를 변경할 수 없기 때문에 결과는 복사하는 것과 매우 유사합니다.
  • 가변 인수는 효과적으로 " 포인터로 "전달 됩니다 . 목록 및 사전과 같은 객체도 객체 참조를 통해 전달되는데, 이는 C가 포인터를 배열로 전달하는 방식과 유사합니다. C 객체와 같이 변경 가능한 객체는 함수에서 대신 변경 될 수 있습니다.

16

알 수 있듯이 변경 가능한 객체가 필요하지만 전역 변수가 도움이 될 수도 있고 이런 종류의 문제를 해결할 수도 있으므로 전역 변수를 확인하는 것이 좋습니다.

http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

예:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2

5
나는 비슷한 답변을 게시하고 싶었다. 원래 질문자는 그가 원했던 것이 실제로 전역 변수를 사용하고 기능간에 공유한다는 것을 알지 못했을 수도있다. 다음은 내가 공유했을 링크입니다. stackoverflow.com/questions/423379/… @Tim에 대한 답변으로, Stack Overflow는 질문과 답변 사이트 일뿐만 아니라 더 강력하고 미묘한 차이를 가져 오는 방대한 참조 지식 저장소입니다. 더 많은 입력을 가진 활성 위키처럼.
Max P Magee 2016 년

13

여기에 대한 답변에 대한 많은 통찰력이 있지만 여기에 추가 요점이 명확하게 언급되어 있지 않다고 생각합니다. 파이썬 문서에서 인용 https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

"Python에서 함수 내에서만 참조되는 변수는 암시 적으로 전역 적입니다. 변수가 함수 본문의 어느 곳에 나 새로운 값이 할당되면 로컬로 간주됩니다. 변수에 함수 내에 새로운 값이 할당되면, 변수는 암시 적으로 지역적이며 명시 적으로 '글로벌'로 선언해야합니다. 처음에는 조금 놀랍지 만, 고려할 사항은 다음과 같습니다. 할당 된 변수에 전역을 요구하면 의도하지 않은 부작용에 대비할 수 있습니다. 반면에 모든 전역 참조에 전역이 필요한 경우 항상 전역을 사용하게되며 내장 함수 또는 가져온 모듈의 구성 요소에 대한 모든 참조를 전역으로 선언해야합니다. 부작용을 식별하기위한 글로벌 선언의 유용성을 무너 뜨릴 것입니다. "

가변 객체를 함수에 전달할 때도 여전히 적용됩니다. 그리고 객체에 할당하는 것과 함수의 객체에서 작동하는 것 사이의 행동 차이가 나는 이유를 분명히 설명합니다.

def test(l):
    print "Received", l , id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

제공합니다 :

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

따라서 전역으로 선언되지 않은 전역 변수에 할당하면 새 로컬 객체가 만들어지고 원래 객체에 대한 링크가 끊어집니다.


10

다음은 pass by object파이썬에서 사용되는 개념에 대한 간단한 설명입니다 .
객체를 함수에 전달할 때마다 객체 자체가 전달됩니다 (파이썬의 객체는 실제로 다른 프로그래밍 언어에서 값을 호출하는 것입니다).이 객체에 대한 참조는 아닙니다. 다시 말해, 전화 할 때 :

def change_me(list):
   list = [1, 2, 3]

my_list = [0, 1]
change_me(my_list)

실제 객체-[0, 1] (다른 프로그래밍 언어에서는 값이라고 함)이 전달되고 있습니다. 실제로 함수 change_me는 다음과 같은 작업을 시도합니다.

[0, 1] = [1, 2, 3]

분명히 함수에 전달 된 객체는 변경되지 않습니다. 함수가 다음과 같은 경우 :

def change_me(list):
   list.append(2)

그런 다음 전화 결과는 다음과 같습니다.

[0, 1].append(2)

분명히 개체가 변경됩니다. 이 답변이 잘 설명되어 있습니다.


2
문제는 과제가 예상 한 것과 다른 일을한다는 것입니다. list = [1, 2, 3]재사용 원인 list뭔가 다른 이름을하고 원래 전달 된 객체를 망각. 그러나, 당신은 시도 할 수 있습니다 list[:] = [1, 2, 3]방법으로 ( list이름을 잘못 변수입니다에 대해 생각하는 것은. [0, 1] = [1, 2, 3]완전한 넌센스입니다 어쨌든, 수단 어떻게 생각하십니까. 객체 자체가 전달됩니다 당신의 의견에 함수에 복사됩니다 무엇?
pepr

@pepr 객체는 리터럴이 아닙니다. 그것들은 대상입니다. 그들에 대해 이야기 할 수있는 유일한 방법은 그들에게 이름을주는 것입니다. 그렇기 때문에 이해하기가 너무 간단하지만 설명하기가 엄청나게 복잡한 이유입니다. :-)
Veky

@Veky : 알고 있습니다. 어쨌든 목록 리터럴은 목록 개체로 변환됩니다. 실제로, 파이썬의 모든 객체는 이름없이 존재할 수 있으며, 이름이 지정되지 않은 경우에도 사용될 수 있습니다. 그리고 당신은 그것들을 익명의 객체라고 생각할 수 있습니다. 객체가 목록의 요소가되는 것을 생각하십시오. 그들은 이름이 필요하지 않습니다. 목록을 색인화하거나 반복하여 액세스 할 수 있습니다. 어쨌든, 나는 [0, 1] = [1, 2, 3]단지 나쁜 예 라고 주장한다 . 파이썬에는 그런 것이 없습니다.
pepr

@pepr : 필연적으로 파이썬 정의 이름을 의미하지는 않으며 단지 일반 이름을 의미합니다. 물론 목록 alist[2]의 세 번째 요소의 이름으로 간주됩니다. 그러나 나는 당신의 문제가 무엇인지 오해했다고 생각합니다. :-)
Veky

아아 내 영어는 분명히 내 파이썬보다 훨씬 나쁩니다. :-) 한 번 더 시도하겠습니다. 난 그냥 당신이 그들에 대해 이야기하기 위해 개체 이름을 부여해야한다고 말했다. 그 "이름"이란 "파이썬에서 정의한 이름"을 의미하지는 않았습니다. 파이썬 메커니즘을 알고 있으므로 걱정하지 마십시오.
Veky

8

파이썬 에서이 기능이 어떻게 작동하는지에 대한 모든 훌륭한 설명 외에도 문제에 대한 간단한 제안은 보이지 않습니다. 객체와 인스턴스를 만드는 것처럼 보이는 것처럼 인스턴스 변수를 처리하고 변경하는 pythonic 방법은 다음과 같습니다.

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.Change()
        print self.variable

    def Change(self):
        self.variable = 'Changed'

인스턴스 메소드에서는 일반적으로 self인스턴스 속성에 액세스 하는 것을 나타냅니다. 인스턴스 속성을 설정 __init__하고 인스턴스 메소드에서 읽거나 변경하는 것이 일반적 입니다. 그렇기 때문에 여러분이 selfals에 첫 번째 인수를 전달하는 이유 def Change입니다.

또 다른 해결책은 다음과 같은 정적 메소드를 작성하는 것입니다.

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.variable = PassByReference.Change(self.variable)
        print self.variable

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var

6

언어가 가능하지는 않지만 참조로 객체를 전달하는 작은 트릭이 있습니다. Java에서도 작동하며 하나의 항목이있는 목록입니다. ;-)

class PassByReference:
    def __init__(self, name):
        self.name = name

def changeRef(ref):
    ref[0] = PassByReference('Michael')

obj = PassByReference('Peter')
print obj.name

p = [obj] # A pointer to obj! ;-)
changeRef(p)

print p[0].name # p->name

추악한 해킹이지만 작동합니다. ;-피


p는 객체를 저장하는 가변 목록 객체를 참조합니다 obj. 참조 'p'는로 전달됩니다 changeRef. 내부 changeRef에서 ref가리키는 동일한 목록 객체를 p가리키는 새 참조가 작성됩니다 (새 참조가 호출 됨 ) . 그러나 목록은 변경 가능하므로 목록에 대한 변경 사항은 참조 모두에서 볼 수 있습니다 . 이 경우 ref참조를 사용하여 인덱스 0에서 오브젝트를 변경하여 이후에 PassByReference('Michael')오브젝트를 저장 합니다. 를 사용하여 목록 개체를 ref변경했지만이 변경 사항은에 표시됩니다 p.
Minh Tran

그래서 지금, 참조 pref단일 객체를 저장하는 목록 개체를 가리킨 PassByReference('Michael'). 따라서을 p[0].name반환합니다 Michael. 물론, ref이제 범위를 벗어 났으며 가비지 수집되었지만 모두 동일 할 수 있습니다.
Minh Tran

당신은 할 수 없습니다 , 전용 인스턴스 변수를 변경 name원래의, PassByReference기준과 관련된 객체 obj불구하고. 실제로 obj.name는을 반환 Peter합니다. 위에서 언급 한 의견은 그 정의 Mark Ransom가 주어진 것으로 가정한다 .
Minh Tran

요컨대, 나는 그것이 해킹 이라는 것에 동의하지 않는다 . 리스트에서 하나의 PassByReference오브젝트를 다른 PassByReference오브젝트로 바꾸고 두 오브젝트 중 후자를 참조하기 만하면 됩니다.
Minh Tran

5

다음 방법을 사용하여 두 개의 포트란 코드를 Python으로 빠르게 변환했습니다. 사실, 원래의 질문이 제기되었을 때 참조로 전달되지는 않지만 경우에 따라 간단한 해결 방법입니다.

a=0
b=0
c=0
def myfunc(a,b,c):
    a=1
    b=2
    c=3
    return a,b,c

a,b,c = myfunc(a,b,c)
print a,b,c

예, 이것은 내 유스 케이스에서도 '통과 기준'을 해결합니다. 기본적으로 a에서 값을 정리 dict하고를 반환하는 함수가 dict있습니다. 그러나 정리하는 동안 시스템의 일부를 다시 빌드해야합니다. 따라서이 기능은 청소 된 상태로 되돌려 dict야 할뿐만 아니라 재 구축 신호를 보낼 수 있어야합니다. bool참조 로 전달하려고했지만 작동하지 않습니다. 이 문제를 해결하는 방법을 알아 내면서 해킹 / 해결 방법 (IMHO)이 아닌 솔루션 (기본적으로 튜플 반환)이 가장 효과적이라는 것을 알았습니다.
kasimir

3

참조로 전달하는 것은 파이썬에 잘 맞지 않으며 거의 ​​사용되지 않아야하지만 실제로는 현재 로컬 변수에 할당 된 객체를 가져 오거나 호출 된 함수 내부에서 로컬 변수를 다시 할당하기 위해 작동 할 수있는 해결 방법이 있습니다.

기본 아이디어는 해당 액세스를 수행 할 수 있고 다른 함수에 객체로 전달되거나 클래스에 저장 될 수있는 함수를 갖는 것입니다.

한 가지 방법은 랩퍼 함수에서 ( global글로벌 변수) 또는 nonlocal(함수의 로컬 변수)를 사용하는 것입니다.

def change(wrapper):
    wrapper(7)

x = 5
def setter(val):
    global x
    x = val
print(x)

del변수 를 읽고 쓰는 데 동일한 아이디어가 적용됩니다 .

읽기 만하면 lambda: x호출 할 때 x의 현재 값을 반환하는 호출 가능을 반환 하는 짧은 방법이 있습니다 . 이것은 먼 옛날 언어에서 사용 된 "이름으로 전화"와 다소 비슷합니다.

변수에 액세스하기 위해 3 개의 래퍼를 전달하는 것은 다소 까다로워서 프록시 속성이있는 클래스로 래핑 될 수 있습니다.

class ByRef:
    def __init__(self, r, w, d):
        self._read = r
        self._write = w
        self._delete = d
    def set(self, val):
        self._write(val)
    def get(self):
        return self._read()
    def remove(self):
        self._delete()
    wrapped = property(get, set, remove)

# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15

파이썬의 "반사"지원을 통해 해당 범위에서 명시 적으로 함수를 정의하지 않고도 주어진 범위에서 이름 / 변수를 재 할당 할 수있는 객체를 얻을 수 있습니다.

class ByRef:
    def __init__(self, locs, name):
        self._locs = locs
        self._name = name
    def set(self, val):
        self._locs[self._name] = val
    def get(self):
        return self._locs[self._name]
    def remove(self):
        del self._locs[self._name]
    wrapped = property(get, set, remove)

def change(x):
    x.wrapped = 7

def test_me():
    x = 6
    print(x)
    change(ByRef(locals(), "x"))
    print(x)

여기서 ByRef클래스는 사전 액세스를 래핑합니다. 따라서 속성 액세스 wrapped는 전달 된 사전의 항목 액세스로 변환됩니다. 내장 결과 locals와 로컬 변수의 이름을 전달하면 로컬 변수에 액세스하게됩니다. 3.5의 python 문서는 사전을 변경해도 작동하지 않을 수도 있지만 나에게 도움이되는 것으로 보입니다.


3

파이썬이 값과 그에 대한 참조를 처리하는 방식에서 임의의 인스턴스 속성을 참조 할 수있는 유일한 방법은 이름입니다

class PassByReferenceIsh:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print self.variable

    def change(self, var):
        self.__dict__[var] = 'Changed'

실제 코드에서는 물론 dict 조회에 오류 검사를 추가합니다.


3

사전은 참조로 전달되므로 dict 변수를 사용하여 참조 된 값을 그 안에 저장할 수 있습니다.

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!" # reference any string (errors, e.t.c). ref['msg'] is string
    return result # return the sum

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the return value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value

3

Python의 Pass-By-Reference는 C ++ / Java의 참조에 의한 pass의 개념과는 상당히 다릅니다.

  • Java & C # : 기본 유형 (문자열 포함) 값으로 전달 (복사), 참조 유형은 참조 (주소 사본)로 전달되므로 호출 된 함수의 매개 변수에서 작성된 모든 변경 사항은 호출자에게 표시됩니다.
  • C ++ : 참조 별 또는 값별이 모두 허용됩니다. 매개 변수가 참조로 전달 된 경우 매개 변수가 const로 전달되었는지 여부에 따라 매개 변수를 수정하거나 수정할 수 없습니다. 그러나 const 또는 not 매개 변수는 객체에 대한 참조를 유지하며 호출 된 함수 내에서 다른 객체를 가리 키도록 참조를 할당 할 수 없습니다.
  • Python : Python은 "객체 참조에 의한 통과"이며, "객체 참조는 값으로 전달됩니다."[읽기] 1. 호출자와 함수는 모두 동일한 객체를 참조하지만 함수의 매개 변수는 호출자의 객체 사본을 보유하는 새로운 변수입니다. C ++과 마찬가지로 매개 변수는 수정되거나 기능하지 않을 수 있습니다. 이는 전달 된 객체의 유형에 따라 다릅니다. 예를 들어; 불변 객체 유형은 호출 된 함수에서 수정할 수 없지만 변경 가능한 객체는 업데이트하거나 다시 초기화 할 수 있습니다. 변경 가능한 변수를 업데이트하거나 재 할당 / 재 초기화하는 것의 중요한 차이점은 업데이트 된 값은 호출 된 함수에 다시 반영되지만 다시 초기화 된 값은 그렇지 않습니다. 새로운 객체를 변경 가능한 변수에 할당하는 범위는 파이썬의 함수에 국한됩니다. @ blair-conrad가 제공 한 예는 이것을 이해하는 데 좋습니다.

1
오래되었지만 나는 그것을 수정해야한다고 생각합니다. 문자열은 값이 아닌 Java와 C # 모두에서 참조로 전달됩니다.
John

2

예제는 객체 지향적이므로 비슷한 결과를 얻기 위해 다음과 같이 변경할 수 있습니다.

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print(self.variable)

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

1
이 작동하지만. 참조로 전달되지 않습니다. '객체 참조를 통한 전달'입니다.
Bishwas Mishra

1

내부적으로 객체 속성이 인스턴스 사전에 저장되기 때문에 객체를 인스턴스로 사용 하여 참조 객체를 저장할 수 있습니다 . 예를 참조하십시오.

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

1

예를 들어 C ++에서 알려진 것처럼 참조를 시뮬레이션하는 방법은 "update"함수를 사용하여 실제 변수 (또는 "name") 대신 전달하는 것입니다.

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

이것은 "아웃-아웃 참조"또는 여러 스레드 / 프로세스가있는 상황 (업데이트 기능 스레드 / 멀티 프로세싱을 안전하게 함)에 주로 유용합니다.

분명히 위 의 값을 읽을 수는 없으며 업데이트 만 가능합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.