874

이를 지원하는 언어로 여러 값을 반환하는 표준 방법은 종종튜플 링.

옵션 : 튜플 사용하기

이 간단한 예제를 생각해보십시오.

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0,y1,y2)

그러나 반환 된 값의 수가 증가하면 문제가 신속하게 해결됩니다. 4 개 또는 5 개의 값을 반환하려면 어떻게해야합니까? 물론, 당신은 그들을 묶어 둘 수 있지만, 어떤 가치가 있는지를 잊기 쉽습니다. 당신이 그들을 받고 싶을 때마다 그것들을 푸는 것이 오히려 추한 것입니다.

옵션 : 사전 사용

다음 논리적 인 단계는 일종의 '레코드 표기법'을 소개하는 것 같습니다. 파이썬에서는 이것을하기위한 확실한 방법은dict.

다음을 고려하세요:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

(편집 - 그냥 분명히, y0, y1 및 y2 추상 식별자 의미입니다. 실제로 지적한 의미있는 식별자를 사용하여 지적한대로)

이제 우리는 반환 된 객체의 특정 멤버를 프로젝션 할 수있는 메커니즘을 가지고 있습니다. 예를 들어,

result['y0']

옵션 : 클래스 사용

그러나 다른 옵션이 있습니다. 대신 특수 구조를 반환 할 수 있습니다. 나는 이것을 파이썬의 맥락에서 설명했다. 그러나 다른 언어에도 적용 할 수있을 것이라고 확신한다. 실제로, C에서 일하고 있다면 이것이 유일한 옵션 일 것입니다. 여기에 간다 :

class ReturnValue(object):
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return ReturnValue(y0, y1, y2)

파이썬에서는 앞의 두 가지가 아마도 배관과 관련하여 매우 유사 할 것입니다.{ y0, y1, y2 }내부적으로 엔트리가 끝난다.__dict__~의ReturnValue.

Python에서 제공하는 추가 기능 중 하나가 작은 객체 인 경우__slots__속성. 클래스는 다음과 같이 표현 될 수 있습니다.

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

로부터Python Reference Manual:

그만큼__slots__선언은 일련의 인스턴스 변수를 취하고 각 인스턴스에 각 변수에 대한 값을 보유하기에 충분한 공간을 예약합니다. 공간이 절약됩니다. 왜냐하면__dict__각 인스턴스에 대해 만들어지지 않습니다.

옵션 : 목록 사용

내가 간과 한 또 다른 제안은 도마뱀 빌 (Bill the Lizard)

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

그래도 내가 가장 좋아하지 않는 방법입니다. 나는 하스켈에 노출되면서 오염 된 것 같지만, 혼합 타입리스트에 대한 생각은 항상 나에게 불편 함을 느꼈다. 이 특별한 예에서리스트는 -not- 혼합 유형이지만 생각할 수 있습니다. 이 방법으로 사용 된리스트는 내가 말할 수있는 한 튜플에 관해서는 아무 것도 얻지 못합니다. 파이썬에서리스트와 튜플의 유일한 차이점은리스트가변하기 쉬운, 튜플은 없습니다. 개인적으로 함수형 프로그래밍의 관례를 따르는 경향이 있습니다. 같은 유형의 요소를 여러 개 사용하고 미리 정해진 유형의 요소를 고정 된 수만큼 튜플을 사용합니다.

의문

오랜 전공 끝에 피할 수없는 질문이옵니다. 어떤 방법 (생각하십니까?)이 가장 좋습니다.

일반적으로 사전 설정 작업이 적기 때문에 사전 경로를 사용하고 있습니다. 그러나 유형 관점에서, 당신은 사전을 나타내는 것이 혼란스럽게되는 것을 피할 수 있기 때문에 클래스 경로를 벗어나는 것이 더 나을 것입니다. 반면에, 파이썬 공동체에는 느낄 수있는 것들이 있습니다.묵시적 인터페이스가 명시 적 인터페이스보다 우선되어야한다.이 시점에서 객체의 유형은 실제로는 관련이 없습니다. 기본적으로 같은 속성이 항상 동일한 의미를 가지게된다는 관습에 의존하기 때문입니다.

그렇다면 파이썬에서 다중 값을 반환하는 방법은 무엇입니까?


  • 훌륭한 예제에서는 변수를 사용합니다.y3, 그러나 y3가 전역으로 선언되지 않으면, 이것은 yNameError: global name 'y3' is not defined아마도 그냥 사용3? - hetepeperfan

14 답변


557

명명 된 튜플이 목적으로 2.6에 추가되었습니다. 참조os.stat유사한 기본 제공 예제입니다.

>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2

최근 버전의 Python 3 (3.6 이상, 내가 생각하기에), 새로운typing도서관에NamedTuple클래스를 사용하여 명명 된 튜플을보다 쉽게 만들고 더 강력하게 만듭니다. 상속자typing.NamedTuple문서 문자열, 기본값 및 유형 주석을 사용할 수 있습니다.

예제 (문서에서) :

class Employee(NamedTuple):  # inherit from collections.NamedTuple
    name: str
    id: int = 3  # default value

employee = Employee('Guido')
assert employee.id == 3


  • 이것은 OP가 고려하지 않은 유일한 정식 구조이고 긴 튜플을 관리하는 문제를 해결하기 때문에 정답 일뿐입니다. 허용 된 것으로 표시해야합니다. - Andy Terra
  • 글쎄, 디자인 근거는namedtuple에 대한 작은 메모리 풋 프린트가 있습니다.질량결과 (DB 쿼리의 결과와 같은 튜플의 긴 목록). 개별 항목의 경우 (문제의 기능이 자주 호출되지 않는 경우) 사전과 수업은 잘됩니다. 그러나 namedtuples은이 경우에도 좋고 / 더 나은 솔루션입니다. - Lutz Prechelt
  • @wom 한 줄로 할 수 있습니다.p=collections.namedtuple('point','x,y')(1,2) - Dave X
  • @wom : 이렇게하지 마십시오. 파이썬은 유일무이 한 노력을하지 않습니다.namedtuple정의 (각 호출은 새로운 호출을 생성 함),namedtuple클래스는 CPU와 메모리 모두에서 상대적으로 비용이 많이 들며 모든 클래스 정의는 본질적으로 순환 참조를 포함합니다 (CPython에서 주기적 GC 실행이 릴리스되기를 기다리고 있습니다). 그것은 또한 불가능하게 만든다.pickle클래스 (따라서 인스턴스를multiprocessing대부분의 경우에). 내 3.6.4 x64에서 클래스를 만들 때마다 ~ 0.337ms가 소모되고 메모리가 1KB 미만으로 줄어들어 인스턴스 절감 효과가 사라집니다. - ShadowRanger
  • @SergeStroobandt - 이것은 표준 라이브러리의 일부이며 기본 라이브러리가 아닙니다. 파이썬이 2.6 이상인 다른 시스템에는 설치되지 않을 수도 있습니다. 아니면 코드의 추가 라인에 반대합니까? - Justin

181

소규모 프로젝트의 경우 튜플을 사용하여 작업하는 것이 가장 쉽습니다. 그렇게되면 관리하기가 너무 어려워지고 전에는 논리적 구조로 그룹 짓기 시작합니다. 그러나 사전과 ReturnValue 객체의 사용은 잘못된 것입니다 (또는 너무 단순합니다).

y0, y1, y2 등의 키를 가진 사전을 반환하는 것은 튜플보다 이점을 제공하지 않습니다. .y0 .y1 .y2 등의 속성을 가진 ReturnValue 인스턴스를 반환해도 튜플보다 유리하지는 않습니다. 어쨌든 튜플 (tuples)을 사용하면 어디든 갈 수 있습니다.

def getImageData(filename):
  [snip]
  return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)

IMHO, 터플을 뛰어 넘는 유일한 좋은 기술은 적절한 메소드와 속성을 가진 실제 객체를 반환하는 것입니다.re.match()또는open(file).


  • 질문 - 거기에 어떤 차이가 있습니까?size, type, dimensions = getImageData(x)(size, type, dimensions) = getImageData(x)? 즉, 배제 된 과제의 왼손 쪽을 감싸는 것이 어떤 차이를 만들어 낼 수 있습니까? - Reb.Cabin
  • @ Reb.Cabin 차이점은 없습니다. 튜플은 쉼표로 표시되며 괄호를 사용하면 여러 항목을 그룹화하는 것입니다. 예를 들어(1)int 인 동안(1,)또는1,튜플입니다. - phil
  • y ", y1, y2 등의 키를 사용하여 사전을 반환하면"기존의 코드를 손상시키지 않고 필드를 반환 된 사전에 추가 할 수 있다는 점에서 장점이 있습니다. - ostrokach

151

많은 답변은 사전이나 목록과 같은 일종의 컬렉션을 반환해야한다고 제안합니다. 추가 구문을 생략하고 쉼표로 구분 된 반환 값을 쓸 수 있습니다. 참고 : 이것은 기술적으로 튜플을 반환합니다.

def f():
    return True, False
x, y = f()
print(x)
print(y)

제공 :

True
False


  • 여전히 컬렉션을 반환 중입니다. 터플입니다. 나는 그것을 더 명백하게하기 위해 괄호를 선호한다. 이 시도:type(f())보고<class 'tuple'>. - Igor
  • @Igor : 이유는 없습니다.tupleaspect 명시 적; 다시 돌아 오는 것이 중요하지 않습니다.tuple이것은 여러 값을 반환하는 관용구입니다. 스왑 이디엄으로 괄호를 생략하는 것과 같은 이유가 있습니다.x, y = y, x, 다중 초기화x, y = 0, 1등; 물론,tuple후드 아래에 있지만, 명시 적으로 만들 이유가 없습니다.tuple전혀 요점은 아닙니다. 파이썬 튜토리얼다중 과제를 소개하다심지어 만지기 훨씬 전에tuple에스. - ShadowRanger

62

나는 사전에 투표한다.

나는 2-3 개 이상의 변수를 반환하는 함수를 만들면 사전에 그 변수를 접을 것입니다. 그렇지 않으면 내가 돌아 오는 것의 순서와 내용을 잊어 버리는 경향이 있습니다.

또한 '특수'구조를 도입하면 코드를 따르기가 더 어려워집니다. (다른 사람이 무엇인지 알아 내기 위해 코드를 검색해야합니다.)

유형 조회에 관심이 있다면 'x-values list'와 같은 설명적인 사전 키를 사용하십시오.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }


  • 수년간의 프로그래밍을 거친 후에 필자는 데이터와 기능의 구조가 요구되는 방향으로 나아 간다. 먼저 기능을 사용하면 항상 리팩토링 할 수 있습니다. - monkut
  • 함수를 여러 번 호출하지 않고 사전에서 값을 얻으려면 어떻게해야합니까? 예를 들어, 다른 함수에서 y1과 y3을 사용하고 싶습니까? - Matt
  • 결과를 별도의 변수에 지정하십시오.result = g(x); other_function(result) - monkut
  • @monkut 예. 또한이 방법을 사용하면 매번 결과의 특정 부분을 구체적으로 참조 할 필요없이 결과에서 다른 인수를 취하는 여러 함수에 결과를 전달할 수 있습니다. - Gnudiff

33

또 다른 옵션은 발전기를 사용하는 것입니다.

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

반환되는 값이 클래스에서의 캡슐화의 후보가되는 경우를 제외하고는 일반적으로 IMHO 튜플이 가장 좋습니다.


  • 이것은 가장 깨끗한 솔루션 인 것처럼 보이며 깨끗한 구문을 사용합니다. 이것에 대한 단점이 있습니까? 모든 반품을 사용하지 않으면 사용하지 않은 & nbsp; & nbsp; 당신을 해칠 때까지 기다리고 있지 않습니까? - Jiminion
  • 이것은 "깨끗한"것이지만, 직관적으로 보일 수는 없습니다. 자동 튜플을 풀면 각각을 트리거한다는 것을 알기 전에이 패턴을 만나지 못한 사람이 어떻게 될까요?yield? - CoreDumpError

25

튜플이 "자연스러운"느낌이들 때마다 튜플을 사용하는 것을 선호합니다. 좌표는 일반적인 예이며, 별도의 객체가 자체적으로 서있을 수 있습니다. 1 축 스케일링 계산만으로, 순서가 중요합니다. 참고 : 그룹의 의미에 악영향을 미치지 않고 항목을 정렬하거나 섞을 수 있다면 튜플을 사용하지 않아야합니다.

그룹화 된 객체가 항상 동일하지 않은 경우에만 사전을 반환 값으로 사용합니다. 선택적 이메일 헤더를 생각해보십시오.

나머지 그룹의 경우, 그룹화 된 오브젝트가 그룹 내에서 고유 한 의미를 가지거나 자체 메소드가있는 완전한 오브젝트가 필요한 경우, 클래스를 사용합니다.


22

나는 선호한다

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

다른 모든 것들이 똑같은 일을하기위한 여분의 코드 일 뿐이라고 생각합니다.


  • 튜플은 언팩하기가 더 쉽습니다 : y0, y1, y2 = g ()해야 할 dict과 함께 : result = g () y0, y1, y2 = result.get (y0 & # 39; get (& # y1 & # 39;), result.get (# y2 & # 39;) 약간 추한 것입니다. 각 솔루션에는 & # 39; 그리고 그것의 & minuses & # 39;. - Oli

22

>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3


  • 아니, 목록이 아닌 터플을 반환하지 않습니다. - Simon Hibbs
  • 구조 조정은그만큼내 의견으로 목록을 반환하기위한 인수 - semiomant

16

파이썬의 튜플 (tuple), 딕트 (dicts), 객체 (object)는 프로그래머가 소규모 데이터 구조 ( "사물")에 대한 형식과 편의성을 원활하게 교환 할 수있게합니다. 나에게있어서, 어떤 것을 표현하는 방법의 선택은 주로 어떻게 구조를 사용할 것인지에 달려있다. C ++에서 사용하는 일반적인 규칙struct데이터 전용 항목 및class메소드를 가진 객체의 경우, 메소드를 합법적으로struct; 내 습관은 파이썬에서 비슷하다.dicttuple대신에struct.

좌표 세트의 경우,tuple한 점보다class또는dict(그리고 당신이 사용할 수있는tuple사전 키로dict훌륭한 스파 스 다차원 배열을 만든다.

내가 물건의 목록을 반복 할 예정이라면, 나는 풀기를 선호한다.tuple반복에 :

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

... 객체 버전이 읽기에 더 어수선하기 때문에 :

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

... 혼자 내버려 둬.dict.

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

그 일이 널리 쓰이고 있으며 코드의 여러 위치에서 이와 유사한 간단한 조작을하는 경우에는 적절한 방법으로 클래스 객체로 만드는 것이 좋습니다.

마지막으로, 파이썬이 아닌 시스템 구성 요소와 데이터를 교환하려고한다면, 나는 종종 그것들을dict이는 JSON 직렬화에 가장 적합하기 때문입니다.


15

일반적으로 "특수 구조"는 실제로 객체의 현명한 현재 상태이며 고유 한 방법을 사용합니다.

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

나는 가능한 한 익명의 구조체의 이름을 찾고 싶다. 의미있는 이름은 일을 더 분명하게 만듭니다.


14

S.Lott의 명명 된 컨테이너 클래스 제안에 +1.

파이썬 2.6 이상에서는명명 된 튜플이러한 컨테이너 클래스를 쉽게 만들 수있는 유용한 방법을 제공하며 결과는 "가볍고 일반 튜플보다 더 많은 메모리가 필요하지 않습니다."


3

파이썬과 같은 언어에서는 일반적으로 새 클래스를 만드는 것보다 오버 헤드가 적기 때문에 사전을 사용합니다.

그러나, 자신이 끊임없이 동일한 변수 세트를 반환한다면, 아마도 그것은 배제 할 새로운 클래스를 포함 할 것입니다.


3

함수에서 값을 전달하고 반환하는 데 dict을 사용합니다.

정의 된대로 변수 형식 사용형태.

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

이것은 나를 위해 그리고 처리 장치를위한 가장 효율적인 방법입니다.

하나의 포인터를 전달하고 하나의 포인터 만 리턴해야합니다.

코드를 변경할 때마다 함수의 수천 개의 인수를 변경할 필요가 없습니다.


2

"최고"는 부분적으로 주관적인 결정입니다. 변경할 수없는 일반적인 경우에는 작은 리턴 세트에 튜플을 사용하십시오. 튜플은 변경 가능성이 요구 사항이 아닌 경우 목록보다 항상 바람직합니다.

더 복잡한 반환 값 또는 형식이 중요한 경우 (즉, 값이 큰 코드) 이름이 지정된 튜플이 더 좋습니다. 가장 복잡한 경우에는 일반적으로 객체가 가장 좋습니다. 그러나 실제로 중요한 상황입니다. 그것이 함수의 끝에서 자연스럽게 가지고있는 것이기 때문에 (예 : 팩토리 패턴) 객체를 반환하는 것이 합리적이라면 객체를 반환하십시오.

현자가 말한대로 :

조숙 한 최적화는 모든 악의 뿌리이다.   그것) 프로그래밍.

연결된 질문


관련된 질문

최근 질문