python 리스트 - 어떻게 파이썬에서 여러 값을 반환합니까?




리턴 함수 (13)

이를 지원하는 언어로 여러 값을 반환하는 정식 방법은 종종 tupling 입니다.

옵션 : 튜플 사용하기

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

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 } 가 결국 ReturnValue 의 내부 __dict__ 에있는 항목이됩니다.

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

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- 혼합 유형이지만 생각할 수 있습니다. 이 방법으로 사용 된 목록은 내가 말할 수있는 한 튜플에 관해서는 아무 것도 얻지 못합니다. 파이썬에서 목록과 튜플의 유일한 차이점은 목록이 mutable 하다는 것입니다. 튜플은 그렇지 않습니다. 개인적으로 함수형 프로그래밍의 관례를 따르는 경향이 있습니다. 같은 유형의 요소를 여러 개 사용하고 미리 정해진 유형의 요소를 고정 된 수만큼 튜플을 사용합니다.

의문

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

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

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


Answers

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

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

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


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

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

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


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

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

현자가 말한대로 :

조숙 한 최적화는 프로그래밍의 모든 악 (또는 적어도 대부분)의 뿌리입니다.


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

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


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

좌표 세트의 경우, 포인트 classtuple 아닌 tuple 사용할 것입니다 (그리고 tuple 을 사전 키로 사용할 수 있다는 점에 유의하십시오. 따라서 딕셔너리는 훌륭한 스파 스 다차원 배열을 만듭니다).

내가 사물의 목록을 반복 할 예정이라면, 나는 반복문에서 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'])

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

마지막으로, 비 파이썬 시스템 구성 요소와 데이터를 교환하려는 경우 JSON 직렬화에 가장 적합하기 때문에 가장 자주 dict 보관할 것입니다.


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

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


함수에서 값을 전달하고 반환하는 데 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}

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

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

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


소규모 프로젝트의 경우 튜플을 사용하여 작업하는 것이 가장 쉽습니다. 그렇게되면 관리하기가 너무 어려워지고 전에는 논리적 구조로 그룹 짓기 시작합니다. 그러나 사전과 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) 에서 얻은 것처럼 적절한 메서드와 속성을 가진 실제 객체를 반환하는 것입니다.


나는 선호한다

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

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


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

>>> 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 튜플이 가장 좋습니다.


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

이 목적으로 명명 된 튜플 이 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 에서 상속 typing.NamedTuple 사용하면 문서화 문자열, 기본값 및 유형 주석을 사용할 수 있습니다.

예제 (문서에서) :

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

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

import time
time.sleep(5)   # Delays for 5 seconds. You can also use a float value.

다음은 무언가가 약 1 분에 한 번 실행되는 또 다른 예제입니다.

import time
while True:
    print("This prints once a minute.")
    time.sleep(60) # Delay for 1 minute (60 seconds).




python coding-style return return-value