etc./StackOverFlow

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

청렴결백한 만능 재주꾼 2021. 10. 9. 02:27
반응형

질문자 :David Sykes


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

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

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



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

  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])

비록 이것이 조금 번거로워 보이지만.


Blair Conrad

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

 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'

Mark Ransom

다른 답변은 다소 길고 복잡하므로 Python이 변수와 매개변수를 처리하는 방식을 설명하기 위해 이 간단한 다이어그램을 만들었습니다. 여기에 이미지 설명 입력


Zenadix

값에 의한 전달이나 참조에 의한 전달이 아니라 객체에 의한 호출입니다. Fredrik Lundh의 다음을 참조하십시오.

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

다음은 중요한 인용문입니다.

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

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


David Cournapeau

참조/값에 의한 대신 할당에 의해 전달되는 항목을 생각하십시오. 그렇게 하면 일반 과제 중에 어떤 일이 발생하는지 이해하는 한 무슨 일이 일어나고 있는지 항상 명확하게 알 수 있습니다.

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

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

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


Daren Thomas

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

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

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

그게 전부입니다. 가변성은 이 질문과 관련이 없습니다.

예시:

 a = 1

이것은 이름 a 를 값 1을 보유하는 정수 유형의 객체에 바인딩합니다.

 b = x

이것은 x 가 현재 바인딩되어 있는 동일한 객체에 b 그 후, b 라는 이름은 x 라는 이름과 더 이상 관련이 없습니다.

Python 3 언어 참조에서 섹션 3.14.2를 참조하세요.

질문의 예를 읽는 방법

질문에 표시된 코드에서 문 self.Change(self.variable) 이름 바인딩 var (함수의 범위에서 Change 값 보유하고있는 객체) 'Original' 과 과제 var = 'Changed' (투입을 Change 함수의 본체는 같은 이름을 다시 할당합니다. 다른 객체에 할당합니다(문자열도 포함하지만 완전히 다른 것일 수 있음).

참조로 전달하는 방법

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

불변 객체(예: bool, 숫자, 문자열)인 경우 변경 가능한 객체로 래핑하는 방법이 있습니다.
이에 대한 빠르고 더러운 솔루션은 요소가 하나인 목록입니다( self.variable [self.variable] 전달하고 함수 수정 var[0] ).
파이썬 적인 접근 방식은 사소한 하나의 속성 클래스를 도입하는 것입니다. 함수는 클래스의 인스턴스를 수신하고 속성을 조작합니다.


Lutz Prechelt

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

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

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

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

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

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

  • 목록과 같은 객체는 변경 가능 합니다. 이것은 객체의 내용이 객체를 가리키는 모든 것에 의해 변경될 수 있음을 의미합니다. 예를 들어, x = []; y = x; x.append(10); print y [10] 을 인쇄합니다. 빈 목록이 생성되었습니다. "x"와 "y"는 모두 같은 목록을 가리킵니다. append 메서드는 목록 개체를 변경(업데이트)하고(예: 데이터베이스에 레코드 추가) 결과는 "x"와 "y" 모두에서 볼 수 있습니다(데이터베이스 업데이트가 해당 데이터베이스에 대한 모든 연결에서 볼 수 있는 것처럼).

문제가 해결되기를 바랍니다.


Raymond Hettinger

기술적으로 Python은 항상 참조 값에 의한 전달을 사용합니다 . 나는 내 진술을 뒷받침하기 위해 다른 대답 을 반복할 것입니다.

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

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

다음은 Python이 참조에 의한 전달을 사용한다는 것을 증명하는 예입니다.

인수 전달의 예시

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

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

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

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


pepr

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

 def Change(self, var): var[0] = 'Changed' variable = ['Original'] self.Change(variable) print variable[0]

(예, 이것이 불편할 수 있다는 것을 압니다. 그러나 때로는 이렇게 하는 것이 충분히 간단합니다.)


AmanicA

(편집 - 블레어는 현재 정확하도록 그의 엄청나게 인기 있는 답변을 업데이트했습니다)

블레어 콘래드(Blair Conrad)가 작성한 가장 많은 표를 얻은 현재 게시물이 그 결과에 관해서는 정확하지만 그 정의에 따라 오해의 소지가 있고 경계선이 정확하지 않다는 점에 주목하는 것이 중요하다고 생각합니다. 사용자가 참조로 전달하거나 값으로 전달할 수 있는 많은 언어(예: C)가 있지만 Python은 그 중 하나가 아닙니다.

David Cournapeau의 답변은 실제 답변을 가리키며 Blair Conrad의 게시물에서 정의가 정확하지 않은 동안 동작이 올바른 것처럼 보이는 이유를 설명합니다.

Python이 값에 의해 전달되는 범위 내에서 모든 언어는 일부 데이터("값" 또는 "참조")가 전송되어야 하므로 값에 의해 전달됩니다. 그러나 이것이 C 프로그래머가 생각할 수 있다는 의미에서 Python이 값에 의해 전달된다는 것을 의미하지는 않습니다.

행동을 원한다면 Blair Conrad의 대답이 좋습니다. 그러나 Python이 값으로 전달되거나 참조로 전달되지 않는 이유를 알고 싶다면 David Cournapeau의 답변을 읽으십시오.


KobeJohn

여기에서 정말 좋은 답변을 얻었습니다.

 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' )

bobobobo

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

  • 변경할 수 없는 인수는 " 값에 따라" 효과적으로 전달됩니다. 정수 및 문자열과 같은 개체는 복사가 아닌 개체 참조로 전달되지만 변경 불가능한 개체를 제자리에서 변경할 수 없기 때문에 효과는 복사본을 만드는 것과 같습니다.
  • 변경 가능한 인수는 " 포인터에 의해 " 효과적으로 전달됩니다. 목록 및 사전과 같은 객체도 객체 참조에 의해 전달됩니다. 이는 C가 배열을 포인터로 전달하는 방식과 유사합니다. 가변 객체는 C 배열과 마찬가지로 함수 내에서 변경될 수 있습니다.

ajknzhol

이 경우 Change 메서드의 var self.variable 에 대한 참조가 할당 var 문자열을 할당합니다. self.variable 가리키지 않습니다. varself.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'] >>>

나는 다른 누군가가 이것을 더 명확히 할 수 있다고 확신합니다.


Mike Mazur

변경할 수 있는 개체가 필요하다고 말할 수 있지만 이러한 종류의 문제를 해결하거나 해결하는 데 도움이 될 수 있으므로 전역 변수를 확인하는 것이 좋습니다.

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

Nuno Aniceto

여기에 대한 답변에 대한 많은 통찰력이 있지만 추가 요점은 여기에 명시적으로 언급되지 않은 것 같습니다. 파이썬 문서에서 인용 https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-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

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


Joop

다음은 Python에서 사용 pass by object 개념에 대한 간단한(희망) 설명입니다.
함수에 객체를 전달할 때마다 이 객체에 대한 참조가 아니라 객체 자체가 전달됩니다(Python의 객체는 실제로 다른 프로그래밍 언어에서 값이라고 부르는 것입니다). 즉, 다음을 호출할 때:

 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)

분명히 개체를 변경할 것입니다. 이 답변은 그것을 잘 설명합니다.


matino

이 항목이 Python에서 어떻게 작동하는지에 대한 모든 훌륭한 설명을 제외하고는 문제에 대한 간단한 제안을 볼 수 없습니다. 객체와 인스턴스를 생성하는 것처럼 보이지만 인스턴스 변수를 처리하고 변경하는 파이썬적인 방법은 다음과 같습니다.

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

인스턴스 메서드에서 일반적으로 인스턴스 속성에 액세스 self __init__ 에서 인스턴스 속성을 설정하고 인스턴스 메소드에서 읽거나 변경하는 것은 정상입니다. def Change 의 첫 번째 인수로 self 를 전달하는 이유이기도 합니다.

또 다른 솔루션은 다음과 같은 정적 메서드를 만드는 것입니다.

 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

Dolf Andringa

언어가 가능하지 않더라도 참조로 개체를 전달하는 약간의 트릭이 있습니다. 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

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


itmuckel

다음 방법을 사용하여 몇 가지 Fortran 코드를 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

Brad Porter

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

 class PassByReferenceIsh: def __init__(self): self.variable = 'Original' self.change('variable') print self.variable def change(self, var): self.__dict__[var] = 'Changed'

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


mARK bLOORE

딕셔너리는 참조로 전달되기 때문에 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!" return result 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 returned value print("multi: ", ref['multi']) # a referenced value print("msg: ", ref['msg']) # a referenced value

Liakos

귀하의 예제는 객체 지향이므로 다음과 같이 변경하여 유사한 결과를 얻을 수 있습니다.

 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'

Jesse Hogan

예를 들어 C++에서 알려진 참조를 시뮬레이션하는 접근 방식은 아무데도 언급되지 않은 것 같기 때문에 "업데이트" 기능을 사용하고 실제 변수(또는 오히려 "이름") 대신 전달하는 것입니다.

 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

이것은 "외부 전용 참조" 또는 다중 스레드/프로세스가 있는 상황에서 주로 유용합니다(업데이트 기능 스레드/다중 처리를 안전하게 만듦으로써).

분명히 위의 경우 값 읽기 가 허용되지 않고 업데이트만 가능합니다.


Daniel Jour

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

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

한 가지 방법은 global (전역 변수의 경우) 또는 nonlocal 지역(함수의 지역 변수의 경우)을 사용하는 것입니다.

 def change(wrapper): wrapper(7) x = 5 def setter(val): global x x = val print(x)

같은 아이디어는 읽고 작동 del 변수를 정 했나요.

lambda: x 사용하는 더 짧은 방법이 있습니다. 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

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

 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 문서에서는 사전을 변경하는 것이 작동하지 않을 수 있다고 조언하지만 저에게는 효과가 있는 것 같습니다.


textshell

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

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

Alok Garg

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

 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)

sergzach

저는 어제 시작한 Python을 처음 사용합니다(45년 동안 프로그래밍을 해왔지만).

나는 두 개의 소위 out-parameters를 갖고 싶어하는 함수를 작성하고 있었기 때문에 여기에 왔습니다. 매개변수가 하나뿐이라면 Python에서 참조/값이 작동하는 방식을 확인하는 데 지금 당장 전화를 끊지 않을 것입니다. 대신 함수의 반환 값을 사용했을 것입니다. 그러나 두 개의 그러한 out-parameters가 필요했기 때문에 나는 그것을 분류할 필요가 있다고 느꼈습니다.

이 게시물에서 나는 내 상황을 어떻게 해결했는지 보여줄 것입니다. 아마도 여기에 오는 다른 사람들은 주제 질문에 대한 정확한 답변이 아닐지라도 그것이 가치 있다는 것을 알게 될 것입니다. 물론 경험 많은 Python 프로그래머는 내가 사용한 솔루션에 대해 이미 알고 있지만 저에게는 생소했습니다.

여기 답변에서 Python이 이와 관련하여 Javascript와 약간 유사하게 작동하고 참조 기능을 원하는 경우 해결 방법을 사용해야 한다는 것을 빠르게 알 수 있습니다.

하지만 파이썬에서 이전에 다른 언어에서는 본 적이 없는 깔끔한 것을 발견했습니다. 즉, 다음과 같이 간단한 쉼표로 구분된 방식으로 함수에서 둘 이상의 값을 반환할 수 있습니다.

 def somefunction(p): a=p+1 b=p+2 c=-p return a, b, c

호출 측에서 이와 유사하게 처리할 수 있습니다.

 x, y, z = somefunction(w)

그것만으로도 충분했고 저는 만족했습니다. 일부 해결 방법을 사용할 필요가 없습니다.

다른 언어에서는 물론 많은 값을 반환할 수도 있지만 일반적으로 개체의 from에서 반환하므로 그에 따라 호출 측을 조정해야 합니다.

이를 수행하는 Python 방식은 훌륭하고 간단했습니다.

참조로 더 많이 모방하려면 다음과 같이 할 수 있습니다.

 def somefunction(a, b, c): a = a * 2 b = b + a c = a * b * c return a, b, c x = 3 y = 5 z = 10 print(F"Before : {x}, {y}, {z}") x, y, z = somefunction(x, y, z) print(F"After : {x}, {y}, {z}")

이 결과를 제공하는

이전 : 3, 5, 10  
이후 : 6, 11, 660  

Magnus

또는 ctypes witch를 사용할 수 있습니다.

 import ctypes def f(a): a.value=2398 ## resign the value in a function a = ctypes.c_int(0) print("pre f", a) f(a) print("post f", a)

as는 ac int이고 파이썬 정수가 아니며 참조에 의해 명백하게 전달됩니다. 그러나 이상한 일이 발생할 수 있으므로 주의해야 하므로 권장하지 않습니다.


Julian wandhoven

가장 신뢰할 수 있는 방법은 아니지만 이 방법이 작동합니다. 일반적으로 원하지 않는 내장 str 함수를 오버로드하고 있다는 점을 명심하십시오.

 import builtins class sstr(str): def __str__(self): if hasattr(self, 'changed'): return self.changed return self def change(self, value): self.changed = value builtins.str = sstr def change_the_value(val): val.change('After') val = str('Before') print (val) change_the_value(val) print (val)

Jop Knoppers

데이터 클래스 는 어떻습니까? 또한 유형 제한("유형 힌트"라고도 함)을 적용할 수 있습니다.

 from dataclasses import dataclass @dataclass class Holder: obj: your_type # Need any type? Use "obj: object" then. def foo(ref: Holder): ref.obj = do_something()

대부분의 경우 사용하지 않는 것이 좋습니다.

그러나 컨텍스트 에 대해 이야기할 때 그런 식으로 알 가치가 있습니다.

하지만 명시적 컨텍스트 클래스를 디자인할 수 있습니다. 프로토타입을 만들 때 앞뒤로 직렬화하기 쉽기 때문에 데이터 클래스를 선호합니다.

건배!


Stepan Dyatkovskiy

출처 : http:www.stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference

반응형