Nice programing

함수에서 여러 값을 반환하려면 어떻게합니까?

nicepro 2020. 9. 27. 14:03
반응형

함수에서 여러 값을 반환하려면 어떻게합니까? [닫은]


여러 값을 지원하는 언어로 반환하는 표준 방법은 종종 tupling 입니다.

옵션 : 튜플 사용

이 사소한 예를 고려하십시오.

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

그러나 반환되는 값의 수가 증가하면 문제가 빠르게 발생합니다. 4 개 또는 5 개의 값을 반환하려면 어떻게해야합니까? 물론, 당신은 그것들을 계속해서 조정할 수 있지만 어떤 값이 어디에 있는지 잊기 쉽습니다. 원하는 곳에서 포장을 푸는 것도 추악합니다.

옵션 : 사전 사용

다음 논리적 단계는 일종의 '레코드 표기법'을 도입하는 것 같습니다. Python에서이를 수행하는 명백한 방법은 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:
  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

로부터 파이썬 참조 설명서 :

__slots__선언 각 변수에 대한 값을 유지하도록 각각의 인스턴스 인스턴스 변수 보유 충분한 공간의 시퀀스 걸린다. __dict__각 인스턴스에 대해 생성되지 않기 때문에 공간이 절약 됩니다.

옵션 : 데이터 클래스 사용 (Python 3.7 이상)

Python 3.7의 새로운 데이터 클래스를 사용하여 자동으로 추가 된 특수 메서드, 입력 및 기타 유용한 도구로 클래스를 반환합니다.

@dataclass
class Returnvalue:
    y0: int
    y1: float
    y3: int

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

옵션 : 목록 사용

내가 간과했던 또 다른 제안은 Bill the Lizard에서 나왔습니다.

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

이것은 제가 가장 좋아하는 방법입니다. Haskell에 노출되어 더럽혀진 것 같지만 혼합형 목록에 대한 아이디어는 항상 나에게 불편 함을 느꼈습니다. 이 특정 예에서 목록은 혼합 유형이 아니지만 아마도 그럴 수 있습니다.

이런 식으로 사용 된 목록은 내가 말할 수있는 한 튜플과 관련하여 아무것도 얻지 못합니다. 파이썬에서리스트와 튜플의 유일한 차이점은리스트는 가변적 이지만 튜플은 그렇지 않다는 것입니다.

나는 개인적으로 함수형 프로그래밍의 관습을 이어가는 경향이있다. 같은 유형의 요소에 대해서는 목록을 사용하고 미리 결정된 유형의 고정 된 요소에 대해서는 튜플을 사용한다.

질문

긴 서문 뒤에 불가피한 질문이 나온다. 어떤 방법이 가장 좋을까요?

나는 일반적으로 설정 작업이 적기 때문에 사전 경로를 사용하는 것을 발견했습니다. 그러나 유형 관점에서 보면 사전이 무엇을 나타내는 지 혼동을 피하는 데 도움이 될 수 있으므로 클래스 경로를 사용하는 것이 더 나을 수 있습니다.

반면에 파이썬 커뮤니티 에는 명시 적 인터페이스보다 묵시적 인터페이스가 선호되어야한다고 생각하는 일부 가 있습니다 .이 시점에서 객체의 유형은 실제로 관련이 없습니다. 기본적으로 동일한 속성이라는 규칙에 의존하기 때문입니다. 항상 같은 의미를 갖습니다.

그렇다면 파이썬에서 여러 값을 어떻게 반환합니까?


이 목적을 위해 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

In recent versions of Python 3 (3.6+, I think), the new typing library got the NamedTuple class to make named tuples easier to create and more powerful. Inheriting from typing.NamedTuple lets you use docstrings, default values, and type annotations.

Example (From the docs):

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

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

For small projects I find it easiest to work with tuples. When that gets too hard to manage (and not before) I start grouping things into logical structures, however I think your suggested use of dictionaries and ReturnValue objects is wrong (or too simplistic).

Returning a dictionary with keys y0, y1, y2, etc. doesn't offer any advantage over tuples. Returning a ReturnValue instance with properties .y0, .y1, .y2, etc. doesn't offer any advantage over tuples either. You need to start naming things if you want to get anywhere, and you can do that using tuples anyway:

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

IMHO, the only good technique beyond tuples is to return real objects with proper methods and properties, like you get from re.match() or open(file).


A lot of the answers suggest you need to return a collection of some sort, like a dictionary or a list. You could leave off the extra syntax and just write out the return values, comma-separated. Note: this technically returns a tuple.

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

gives:

True
False

I vote for the dictionary.

I find that if I make a function that returns anything more than 2-3 variables I'll fold them up in a dictionary. Otherwise I tend to forget the order and content of what I'm returning.

Also, introducing a 'special' structure makes your code more difficult to follow. (Someone else will have to search through the code to find out what it is)

If your concerned about type look up, use descriptive dictionary keys, for example, 'x-values list'.

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

Another option would be using generators:

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

Although IMHO tuples are usually best, except in cases where the values being returned are candidates for encapsulation in a class.


I prefer to use tuples whenever a tuple feels "natural"; coordinates are a typical example, where the separate objects can stand on their own, e.g. in one-axis only scaling calculations, and the order is important. Note: if I can sort or shuffle the items without an adverse effect to the meaning of the group, then I probably shouldn't use a tuple.

I use dictionaries as a return value only when the grouped objects aren't always the same. Think optional email headers.

For the rest of the cases, where the grouped objects have inherent meaning inside the group or a fully-fledged object with its own methods is needed, I use a class.


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

I prefer:

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

It seems everything else is just extra code to do the same thing.


Generally, the "specialized structure" actually IS a sensible current state of an object, with its own methods.

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

I like to find names for anonymous structures where possible. Meaningful names make things more clear.


Python's tuples, dicts, and objects offer the programmer a smooth tradeoff between formality and convenience for small data structures ("things"). For me, the choice of how to represent a thing is dictated mainly by how I'm going to use the structure. In C++, it's a common convention to use struct for data-only items and class for objects with methods, even though you can legally put methods on a struct; my habit is similar in Python, with dict and tuple in place of struct.

For coordinate sets, I'll use a tuple rather than a point class or a dict (and note that you can use a tuple as a dictionary key, so dicts make great sparse multidimensional arrays).

If I'm going to be iterating over a list of things, I prefer unpacking tuples on the iteration:

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

...as the object version is more cluttered to read:

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

...let alone the dict.

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

If the thing is widely used, and you find yourself doing similar non-trivial operations on it in multiple places in the code, then it's usually worthwhile to make it a class object with appropriate methods.

Finally, if I'm going to be exchanging data with non-Python system components, I'll most often keep them in a dict because that's best suited to JSON serialization.


+1 on S.Lott's suggestion of a named container class.

For Python 2.6 and up, a named tuple provides a useful way of easily creating these container classes, and the results are "lightweight and require no more memory than regular tuples".


In languages like Python, I would usually use a dictionary as it involves less overhead than creating a new class.

However, if I find myself constantly returning the same set of variables, then that probably involves a new class that I'll factor out.


I would use a dict to pass and return values from a function:

Use variable form as defined in form.

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}

This is the most efficient way for me and for processing unit.

You have to pass just one pointer in and return just one pointer out.

You do not have to change functions' (thousands of them) arguments whenever you make a change in your code.


"Best" is a partially subjective decision. Use tuples for small return sets in the general case where an immutable is acceptable. A tuple is always preferable to a list when mutability is not a requirement.

For more complex return values, or for the case where formality is valuable (i.e. high value code) a named tuple is better. For the most complex case an object is usually best. However, it's really the situation that matters. If it makes sense to return an object because that is what you naturally have at the end of the function (e.g. Factory pattern) then return the object.

As the wise man said:

Premature optimization is the root of all evil (or at least most of it) in programming.

참고URL : https://stackoverflow.com/questions/354883/how-do-i-return-multiple-values-from-a-function

반응형