상세 컨텐츠

본문 제목

[python]함수의 인자 형태와 순서 / (non)default value parameter, *args, **kwargs

언어/Python

by moonionn 2021. 3. 17. 23:32

본문

파이썬의 함수는 정말 다양한 형태의 인자를 받습니다.

인자값의 기본값 유무에 따라

non-default value parameterdefault value parameter로 나뉘기도 하면서,

이 두 인자형태를 여러개 받을 수 있는 *args**kwargs로 나뉘기도 합니다.

 

좀 더 정확한 설명을 위해 (non)/default value parameter부터 살펴봅시다.

 


non-default value parameter

non-default value parameter는 미리 값이 정해지지 않은 인자입니다.

가장 흔하게 쓰이는 인자타입이기도 한데,

함수를 호출할 때 인자의 순서대로 인자값을 넣어주어야 합니다.

def use_non_default_value_parameter(name, occupation):
    return f'내 이름은 {name}, {occupation}이죠.'

# 의도대로 인자의 순서를 맞추지 않으면...
print(use_non_default_value_parameter('탐정', '코난'))

# 결과
# 내 이름은 탐정, 코난이죠.

 

위 결과에서 보여지는 non-default value parameter의 단점은 아래와 같습니다.

  • 논리적 오류를 발생시킬 가능성이 있습니다.
  • 인자에 어떤 타입이 들어올지 몰라 가독성이 떨어집니다.

하지만 순서만 잘 맞춘다면 정말 자유롭게 값을 받아 쓸 수 있습니다.

 


default value parameter

함수 선언시 미리 값이 정해지는 인자입니다.

기본값이 존재하는 인자를 받을때 사용하며 

코드의 중복을 줄이고 가독성을 높이기 위해 주로 사용합니다.

def use_default_value_parameter(count, last='땡!'):
    for i in range(count, 0, -1):
        print(i)
    print(last)

use_default_value_parameter(5)
# 결과
5
4
3
2
1
땡!

 

물론 default value가 정해졌다 해도

언제든 함수 사용시 값을 변경할 수 있습니다.

def use_default_value_parameter(count, last='땡!'):
    for i in range(count, 0, -1):
        print(i)
    print(last)

use_default_value_parameter(5, '1의 반.. 1의 반의 반...')
# 결과
5
4
3
2
1
1의 반.. 1의 반의 반...

 

이 이유때문에

default value parameter는 항상 non-default value parameter보다 뒤에 위치해야 합니다.

 

2개의 인자를 가진 func 라는 함수를 작성해봅시다.

하나는 기본값을 가진 인자고, 하나는 그렇지 않은 인자입니다.

# 잘못된 코드

def func(x = 1, y):
    print(x, y)

func(2)

위 코드는 y의 값을 2로 지정해줄 의도였지만 

default value를 가진 parameter도 값이 변경 가능하기 때문에

func(2)의 2는 x에게 할당됩니다.

따라서 y는 아무런 값을 할당받지 못하니 에러가 나고 맙니다.

 

# SyntaxError: non-default argument follows default argument

 


*args

non-default value parameter의 개수가 유동적일때 사용합니다.

입력받은 인자들은 튜플 형태로 저장됩니다.

def func(*args):
    return args

print(func(1, 3, ['1', 2], {'a':1}, 1000.10))
# 결과: (1, 3, ['1', 2], {'a': 1}, 1000.1)

 

따라서 *args 인자 뒤에 다른 인자가 있으면 에러가 납니다.

*args는 앞의 인자에 할당하고 남은 나머지 전부를 가져가기 때문에 

그 뒤의 인자가 할당받을 것이 없기 때문입니다.

# 에러가 날 함수

def func_param_with_var_args(name, *args, age):
    print(f"name={name}")
    print(f"args={args}")
    print(f"age={age}")

func_param_with_var_args("정우성", "01012341234", "seoul", 20)

# '정우성'은 name에 배정되고, '01012341234' 부터 20까지 *args에 배정된다.
#결과: TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'

 

하지만 *args 뒤에 default value를 가진 인자가 오면

해당 인자는 args에 포함되지 않습니다.

뒤에 언급되겠지만,

default value parameter는 *args가 아니라 **kwargs에 포함되기 때문입니다.

# 수정된 함수

def func_param_with_var_args(name, *args, age=20):
    print(f"name={name}")
    print(f"args={args}")
    print(f"age={age}")

func_param_with_var_args("정우성", "01012341234", "seoul")
# 결과

# name=정우성
# args=('01012341234', 'seoul')
# age=20

 


**kwargs

default value parameter의 개수가 유동적일때 사용합니다.

입력받은 인자들은 딕셔너리 형태로 저장됩니다.

def func(**kwargs):
    return kwargs

print(func(lang='python', number=1000, dictionary={'a':1, 'b':2}))
# 결과: {'lang': 'python', 'number': 1000, 'dictionary': {'a': 1, 'b': 2}}

 

 

**kwargs는 *args와 마찬가지로 앞의 인자들이 할당을 받은 후

남은 나머지들을 모두 가져가기 때문에 맨 뒤의 순서에 위치해야 합니다.

**kwargs는 사실상 함수의 인자 중 가장 마지막으로 오는 인자입니다.

따라서 뒤에 다른 인자가 붙으면 syntax error가 발생합니다.

 

# 수정한 함수

def func_param_with_kwargs(name, age, address=0, **kwargs):
    print(f"name={name}")
    print(f"age={age}")
    print(f"kwargs={kwargs}")
    print(f"address={address}")

func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")
# 결과

# name=정우성
# age=20
# kwargs={'mobile': '01012341234'}
# address=seoul

 

(심화) *args, **kwargs, (non)/default value parameter 의 순서

이 네 가지 인자형태를 동시에 받으려면 인자 순서는 어떻게 정해줄까요?

 

조금 복잡하게 느껴질 수도 있지만 간단합니다.

  1. 우선 *args 이전의 인자들이 각자 하나의 값씩을 배정받을 것이고,

  2. 남은 non-default value parameter들은 *args에 포함될 것입니다.

  3. 그럼 이제 default value parameter들만 남는데,

      그 중 함수 선언때 썼던 인자의 이름(key)이 일치하는 게 있으면 먼저 값을 배정받습니다.

  4. 남은 default value parameter들이 **kwargs로 들어갑니다.

def mixed_params(age, name="아이유", *args, address, **kwargs):
    print(f"name={name}")
    print(f"args={args}")
    print(f"age={age}")
    print(f"kwargs={kwargs}")
    print(f"address={address}")

mixed_params(20, "정우성", "01012341234", "male", mobile="01012341234", address="seoul")

 

# 결과

# name=정우성
# args=('01012341234', 'male')
# age=20
# kwargs={'mobile': '01012341234'}
# address=seoul

 

관련글 더보기

댓글 영역