파이썬 가변 인자 함수 (Variadic Function Arguments)

Beginner

This tutorial is from open-source community. Access the source code

소개

이 섹션에서는 가변 인자 함수 (variadic function arguments) 에 대해 다룹니다. 이는 때때로 *args**kwargs로 설명됩니다.

위치 가변 인자 (*args)

임의의 수의 인자를 허용하는 함수는 가변 인자를 사용한다고 합니다. 예를 들어 다음과 같습니다.

def f(x, *args):
    ...

함수 호출.

f(1,2,3,4,5)

추가 인자는 튜플로 전달됩니다.

def f(x, *args):
    ## x -> 1
    ## args -> (2,3,4,5)

키워드 가변 인자 (**kwargs)

함수는 또한 임의의 수의 키워드 인자를 허용할 수 있습니다. 예를 들어 다음과 같습니다.

def f(x, y, **kwargs):
    ...

함수 호출.

f(2, 3, flag=True, mode='fast', header='debug')

추가 키워드는 딕셔너리로 전달됩니다.

def f(x, y, **kwargs):
    ## x -> 2
    ## y -> 3
    ## kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }

둘 다 결합하기

함수는 또한 임의의 수의 가변 키워드 및 비 키워드 인자를 허용할 수 있습니다.

def f(*args, **kwargs):
    ...

함수 호출.

f(2, 3, flag=True, mode='fast', header='debug')

인자는 위치 인자와 키워드 구성 요소로 분리됩니다.

def f(*args, **kwargs):
    ## args = (2, 3)
    ## kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }
    ...

이 함수는 위치 인자 또는 키워드 인자의 모든 조합을 받습니다. 이는 래퍼 (wrapper) 를 작성하거나 다른 함수로 인자를 전달하려는 경우에 사용됩니다.

튜플 (Tuples) 과 딕셔너리 (Dicts) 전달하기

튜플은 가변 인자로 확장될 수 있습니다.

numbers = (2,3,4)
f(1, *numbers)      ## Same as f(1,2,3,4)

딕셔너리도 키워드 인자로 확장될 수 있습니다.

options = {
    'color' : 'red',
    'delimiter' : ',',
    'width' : 400
}
f(data, **options)
## Same as f(data, color='red', delimiter=',', width=400)

연습 문제 7.1: 가변 인자의 간단한 예시

다음 함수를 정의해 보세요:

>>> def avg(x,*more):
        return float(x+sum(more))/(1+len(more))

>>> avg(10,11)
10.5
>>> avg(3,4,5)
4.0
>>> avg(1,2,3,4,5,6)
3.5
>>>

*more 매개변수가 어떻게 모든 추가 인자를 수집하는지 확인하세요.

연습 문제 7.2: 튜플 (tuple) 과 딕셔너리 (dict) 를 인자로 전달하기

파일에서 데이터를 읽어 다음과 같은 튜플을 얻었다고 가정해 봅시다:

>>> data = ('GOOG', 100, 490.1)
>>>

이제 이 데이터를 사용하여 Stock 객체를 생성하고 싶다고 가정해 봅시다. data를 직접 전달하려고 하면 작동하지 않습니다:

>>> from stock import Stock
>>> s = Stock(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Stock.__init__() missing 2 required positional arguments: 'shares' and 'price'
>>>

이것은 대신 *data를 사용하여 쉽게 해결할 수 있습니다. 다음을 시도해 보세요:

>>> s = Stock(*data)
>>> s
Stock('GOOG', 100, 490.1)
>>>

딕셔너리가 있는 경우, 대신 **를 사용할 수 있습니다. 예를 들어:

>>> data = { 'name': 'GOOG', 'shares': 100, 'price': 490.1 }
>>> s = Stock(**data)
Stock('GOOG', 100, 490.1)
>>>

연습 문제 7.3: 인스턴스 (instance) 목록 생성하기

report.py 프로그램에서 다음과 같은 코드를 사용하여 인스턴스 목록을 생성했습니다:

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    with open(filename) as lines:
        portdicts = fileparse.parse_csv(lines,
                               select=['name','shares','price'],
                               types=[str,int,float])

    portfolio = [ Stock(d['name'], d['shares'], d['price'])
                  for d in portdicts ]
    return Portfolio(portfolio)

Stock(**d)를 대신 사용하여 해당 코드를 단순화할 수 있습니다. 변경해 보세요.

연습 문제 7.4: 인자 (argument) 전달

fileparse.parse_csv() 함수는 파일 구분 기호 변경 및 오류 보고를 위한 몇 가지 옵션을 가지고 있습니다. 아마도 위에서 언급한 read_portfolio() 함수에 이러한 옵션을 노출하고 싶을 것입니다. 다음과 같이 변경하세요:

def read_portfolio(filename, **opts):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    with open(filename) as lines:
        portdicts = fileparse.parse_csv(lines,
                                        select=['name','shares','price'],
                                        types=[str,int,float],
                                        **opts)

    portfolio = [ Stock(**d) for d in portdicts ]
    return Portfolio(portfolio)

변경을 완료한 후, 몇 가지 오류가 있는 파일을 읽어보세요:

>>> import report
>>> port = report.read_portfolio('missing.csv')
Row 4: Couldn't convert ['MSFT', '', '51.23']
Row 4: Reason invalid literal for int() with base 10: ''
Row 7: Couldn't convert ['IBM', '', '70.44']
Row 7: Reason invalid literal for int() with base 10: ''
>>>

이제 오류를 숨겨보세요:

>>> import report
>>> port = report.read_portfolio('missing.csv', silence_errors=True)
>>>

요약

축하합니다! 가변 인자 (Variable Arguments) 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.