파이썬에서 참조로 정수 전달


98

파이썬에서 어떻게 정수를 참조로 전달할 수 있습니까?

함수에 전달하는 변수의 값을 수정하고 싶습니다. 나는 파이썬의 모든 것이 가치로 전달된다는 것을 읽었지만 쉬운 트릭이 있어야합니다. 예를 들어 Java Integer에서는 Long, 등 의 참조 유형을 전달할 수 있습니다 .

  1. 어떻게 정수를 함수에 참조로 전달할 수 있습니까?
  2. 모범 사례는 무엇입니까?

'참조'처럼 동작하는 익명의 클래스 (변경 가능)에 int를 래핑하는 약간 복잡한 방법을 참조하십시오. stackoverflow.com/a/1123054/409638 ie ref = type ( '', () , { 'n': 1})
robert

답변:


109

파이썬에서는 그렇게 작동하지 않습니다. 파이썬은 객체에 대한 참조를 전달합니다. 함수 내부에는 객체가 있습니다. 가능하면 해당 객체를 자유롭게 변경할 수 있습니다. 그러나 정수는 변경할 수 없습니다 . 한 가지 해결 방법은 변경 될 수있는 컨테이너에 정수를 전달하는 것입니다.

def change(x):
    x[0] = 3

x = [1]
change(x)
print x

이것은 기껏해야 추악하고 어색하지만 파이썬에서 더 잘할 수는 없습니다. 그 이유는 Python에서 할당 ( =)은 오른쪽의 결과 인 모든 객체를 가져 와서 왼쪽에있는 모든 객체 * (또는 적절한 함수에 전달)에 바인딩하기 때문입니다.

이를 이해하면 함수 내에서 불변 객체의 값을 변경할 수있는 방법이없는 이유를 알 수 있습니다. 불변이기 때문에 속성을 변경할 수 없으며 "변수"에 새 항목을 할당 할 수 없습니다. 값은 실제로 새 객체 (이전 객체와 구별됨)를 만들고 이전 객체가 로컬 네임 스페이스에있는 이름을 지정하기 때문입니다.

일반적으로 해결 방법은 원하는 개체를 반환 하는 것입니다.

def multiply_by_2(x):
    return 2*x

x = 1
x = multiply_by_2(x)

* 위의 첫 번째 예에서는 3실제로 x.__setitem__.


11
"Python은 객체를 전달합니다." 아니요. Python은 참조 (객체에 대한 포인터)를 전달합니다.
user102008 2013

6
@ user102008-공정한 포인트. 이 시점에서 의미는 매우 흐릿 해집니다. 궁극적으로 그들은 "포인터"도 아닙니다. 적어도 .NET에서 가지고있는 것과 같은 의미는 아닙니다 C. (예를 들어, 역 참조 할 필요가 없습니다). 내 멘탈 모델에서는 사물을 "이름"과 "대상"으로 생각하는 것이 더 쉽습니다. 할당은 왼쪽의 "이름"을 오른쪽의 "개체"에 바인딩합니다. 함수를 호출 할 때 "Object"를 전달합니다 (함수 내에서 새 로컬 이름에 효과적으로 바인딩).
mgilson 2013-04-08

물론 이것은 파이썬 참조 가 무엇인지에 대한 설명 이지만 용어에 익숙하지 않은 사람들에게 간결하게 설명하는 방법을 찾는 것은 쉽지 않습니다.
mgilson 2013-04-08

2
용어와 혼동되는 것은 당연합니다. 여기에서는 객체 별 호출로 설명 하고 여기에서는 값에 의한 전달로 설명 합니다 . 다른 곳에서는 그것이 실제로 의미하는 바에 별표가있는 "참조에 의한 통과"라고합니다. 기본적으로 문제는 커뮤니티가 그것을 무엇이라고
부를지

1
Python 참조는 Java 참조와 정확히 동일합니다. 그리고 Java 참조는 객체에 대한 JLS 포인터를 따릅니다. 그리고 기본적으로 Java / Python 참조와 시맨틱의 객체에 대한 C ++ 포인터 사이에는 완전한 bijection이 있으며 다른 어떤 것도이 시맨틱을 설명하지 않습니다. "그들은 역 참조 될 필요가 없습니다."글쎄, .연산자는 단순히 왼쪽을 역 참조합니다. 연산자는 언어마다 다를 수 있습니다.
user102008

31

참조로 전달해야하는 대부분의 경우는 호출자에게 둘 이상의 값을 반환해야하는 경우입니다. "모범 사례"는 여러 반환 값을 사용하는 것입니다. 이는 Java와 같은 언어보다 Python에서 훨씬 더 쉽습니다.

다음은 간단한 예입니다.

def RectToPolar(x, y):
    r = (x ** 2 + y ** 2) ** 0.5
    theta = math.atan2(y, x)
    return r, theta # return 2 things at once

r, theta = RectToPolar(3, 4) # assign 2 things at once

9

값을 직접 전달하는 것이 아니라 전달 된 것처럼 사용합니다.

x = 7
def my_method():
    nonlocal x
    x += 1
my_method()
print(x) # 8

주의 사항 :

  • nonlocal 파이썬 3에서 소개되었습니다.
  • 둘러싸는 범위가 전역 범위 인 경우 global대신을 사용하십시오 nonlocal.

7

실제로 가장 좋은 방법은 한 걸음 물러서서이 작업이 정말로 필요한지 묻는 것입니다. 함수에 전달하는 변수의 값을 수정하려는 이유무엇 입니까?

빠른 해킹을 위해해야 ​​할 경우 가장 빠른 방법은 list정수 를 전달하고 [0]mgilson의 답변에서 알 수 있듯이 정수를 사용할 때마다 사용하는 것입니다.

좀 더 중요한 일을해야한다면 속성 class이있는 a 를 작성하여 int설정하면됩니다. 물론 이것은 당신이 수업과 속성에 대한 좋은 이름을 생각해 내도록 강요합니다. 만약 당신이 아무것도 생각할 수 없다면, 돌아가서 문장을 몇 번 다시 읽은 다음 list.

보다 일반적으로 일부 Java 관용구를 Python으로 직접 이식하려는 경우 잘못하고있는 것입니다. ( static/ 와 같이) 직접 대응하는 것이 있더라도 @staticmethodJava에서 사용하기 때문에 대부분의 Python 프로그램에서 사용하고 싶지 않습니다.


JAVA는 정수를 참조로 전달하지 않습니다 (정수 또는 객체. 박스형 객체도 할당시 대체 됨).
Luis Masuelli 2014 년

@LuisMasuelli 글쎄요, boxed primitves는 객체처럼 취급됩니다. OP가 원하는대로 사용을 방해하는 유일한 것은 상자가 불변이라는 사실입니다. 가변 수준)
Kroltan 2017

이에 대한 좋은 사용 사례는 재귀 함수 내에서 호출 수 (깊이가 아닌 총계)를 계산하는 것입니다. 분기 된 모든 통화에서 증가 할 수있는 번호가 필요합니다. 표준 INT 그냥 잘라하지 않습니다
z33k

4

Python에서 모든 값은 Java의 기본 요소가 아닌 것처럼 참조 (객체에 대한 포인터)입니다. 또한 Java와 마찬가지로 Python은 값으로 만 전달합니다. 따라서 의미 적으로는 거의 동일합니다.

질문에서 Java를 언급했기 때문에 Java에서 원하는 것을 어떻게 달성하는지보고 싶습니다. Java로 표시 할 수 있다면 Python에서도 정확히 동일하게 수행하는 방법을 보여줄 수 있습니다.


4

NumPy와 단일 소자 어레이는 가변하고 수치 파이썬 변수 것처럼 아직 대부분의 목적을 위해, 그것은 평가 될 수있다. 따라서 단일 요소 목록보다 참조 번호 별 컨테이너가 더 편리합니다.

    import numpy as np
    def triple_var_by_ref(x):
        x[0]=x[0]*3
    a=np.array([2])
    triple_var_by_ref(a)
    print(a+1)

산출:

3

4

비단뱀적인 방법은 아닐 수도 있지만 이렇게 할 수 있습니다.

import ctypes

def incr(a):
    a += 1

x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref

똑똑한 사람.
xilpex

3
class PassByReference:
    def Change(self, var):
        self.a = var
        print(self.a)
s=PassByReference()
s.Change(5)     


0

Python에서는 모든 것이 값으로 전달되지만 일부 상태를 수정하려면 메서드에 전달되는 목록 또는 객체 내에서 정수 값을 변경할 수 있습니다.


3
everything is passed by value사실이 아니기 때문이라고 생각 합니다. 문서 인용 :arguments are passed using call by value (where the value is always an object reference, not the value of the object)
Astery

1
목록, 객체 및 사전은 참조로 전달됩니다
AN88

2
이것이 사실이라면, 함수의 매개 변수에 대한 할당은 호출 사이트에 반영됩니다. Astery 인용 된 전달은 값에 의한 것이며 해당 값은 객체 참조입니다.
순환 적

0

정답은 클래스를 사용하고 클래스 내부에 값을 넣는 것입니다. 그러면 원하는대로 정확하게 참조로 전달할 수 있습니다.

class Thing:
  def __init__(self,a):
    self.a = a
def dosomething(ref)
  ref.a += 1

t = Thing(3)
dosomething(t)
print("T is now",t.a)

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