[Pythonic한 코드 작성하기] Python의 가변 인수(*args)와 키워드 인수에 대해 파헤쳐보자
c에서는 *args라는 변수로 매개변수를 받습니다. 파이썬에서도 비슷하게 가변 인수를 제공하고있는데요, 이번 시간에는 가변 인수와 키워드 인수에 대해서 어떻게 파이써닉한 코드를 작성할 수 있을지 알아봅시다!
가변 위치 인수로 코드를 깔끔하게 보이게 하자
선택적인 위치 인수, 이런 파라미터들을 관례적으로 *args
라고 해서 종종 star args라고 합니다. 이런 가변 인수를 받게 만들면 함수의 호출을 더 명확하게 할 수 있고 읽기 힘든 요소들을 없앨 수 있습니다.
아래와 같은 함수가 있다고 해봅시다.
def func(message, value):
if not values:
print(message)
else:
values_str = ', '.join(str(x) for x in values)
print("{}: {}".format(message, values_str))
명확한 함수죠? message와 value를 인자로 받고, 아래와 같이 사용할 수 있습니다.
func('My Message : ;, [1, 2])
func('No value', [])
value에 아무런 값도 넣고싶지 않을 때에는 value 매개변수 자리에 빈 리스트를 넣어주어야 합니다. 꽤 귀찮은 일인데요, 파이썬에서는 * 기호를 마지막 위치의 파라미터 이름 앞에 붙여서 해결할 수 있습니다.
def func(message, *value): # 유일하게 다른 부분
if not values:
print(message)
else:
values_str = ', '.join(str(x) for x in values)
print("{}: {}".format(message, values_str))
이렇게 작성하면 위와 똑같은 예시에서 아래와 같이 작성할 수 있습니다.
func('My Message : ;, 1, 2) # 값들을 전달
func('No value') # 훨씬 명ㄴ확하다
만약 리스트를 가변인수의 인자로 넣어주고 싶을 때에는 * 연산자를 사용하면 됩니다. 그러면 파이썬은 시퀀스에 들어있는 아이템들을 위치 인수로 전달합니다.
lst = [7, 33, 99]
func('List Example : ', *lst)
가변인수 사용핧 때 주의할 점
1. 제너레이터에서는 조심하자!
가변 인수를 받을 때 인수는 항상 튜플로 변환됩니다. 그래서 제너레이터에 * 연산자를 쓰면 제너레이터가 모두 소진될 때 까지 순회됩니다. 결과로 만들어지는 튜플이 제너레이터로부터 생성된 모든 값을 담으므로 메모리를 많이 차지하게되어 프로그램이 제대로 동작하지 않을 수 있습니다.
def get_generator():
for i in range(10):
yield i
def func(*args):
print(args)
it = get_generator()
func(*it)
>>>
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) # 값을 모두 불러옴
2. 코드를 수정하면 호출 코드를 모두 변경하지 않고는 새 위치 인수를 추가하기 힘들다
인수 리스트의 앞쪽에 위치 인수를 추가하면 기존의 호출 코드가 제대로 동작하기 힘들어집니다. 만약 위의 func
함수에서 새로운 위치 인수를 아래와 같이 추가해보았다고 해봅시다.
def func(sequence, message, *value): # 새 위치 인수 sequence 추가
if not values:
print("{}: {}".format(sequence, message))
else:
values_str = ', '.join(str(x) for x in values)
print("{}: {}: {}".format(sequence, message, values_str))
이 코드에서 기본과 같이 func('My message :', 7, 33)
은 제대로 동작하지 않습니다. 이런 버그는 코드에서 예외를 일으키지 않고 계속 실행되기 때문에 바로 발견하기가 어렵습니다. 이런 문제가 생길 가능성을 완전히 없애려면 *args
를 받는 함수를 확장할 때 키워드 전용인수를 사용해야 합니다.
Python의 키워드 인수
파이썬에서 함수를 작성하다보면 쉽게 키워드 인수를 발견하고, 또 사용하고 있을겁니다. 키워드로 인수를 넘기는 방법은 유연성이 있고, 쓰임새가 분명한 코드를 작성하는데 도움이 됩니다.
예를들어 어떤 숫자를 다른 숫자로 나누는 함수를 만들어보자고 해봅시다. 이 함수에서는 ZeroDivisionError
예외를 무시하고 무한대 값을 반환하고 싶을 수도 있고, OverflowError
예외를 무시하고 0을 반환하고 싶을 수도 있게끔 해봅시다.
def safe_division(number, divisor, ignore_overflow, ignore_zero_division):
try:
return number / divisior
except OverflowError:
if ignore_overflow:
return 0
else:
raise
except ZeroDivisionError:
if ignore_zero_division:
return float('inf')
else:
raise
함수를 사용하는 방법은 간단합니다. 아래는 나눗셈에서 일어나는 float
오버플로우를 무시하고 0을 반환하는 코드입니다.
result = safe_division(1, 10**500, True, False)
print(result)
>>>
0.0
위와 같이 코드를 작성하면 두 부울 인수의 위치가 헷갈릴 수 있습니다. 이런 코드의 가독성을 높이는 방법이 바로 키워드 인수를 사용하는 방법입니다.
def safe_division_b(number, divisor,
ignore_overflow=False,
ignore_zero_division = False):
#...
그러면 호출하는 쪽에서 키워드 인수로 특정 연산에는 기본 동작을 덮어쓰고 무시할 플래그를 지정할 수 있습니다.
safe_division_b(1, 10**500, ignore_overflow=True)
safe_division_b(1, 0, ignore_zero_division=True)
여기서 키워드 인수를 강제하는 방법은 바로 * 연산자를 또 ㅍ사용하는 방법입니다. 인수 리스트에 있는 * 기호는 위치 인수의 끝과 키워드 전용 인수의 시작에 위치하면서 키워드 인수에서 키워드 명명을 필수로 하게 할 수 있습니다.
def safe_division_c(number, divisor, *, # * 추가
ignore_overflow=False,
ignore_zero_division=False):
# ...
이제 호출할 때 어떤 키워드인지 명시해주지 않으면 타입 에러가 발생합니다.
safe_division_c(1, 10**500, True, False)
>>>
Traceback (most recent call last):
File "/Users/a1101497/studystudy/main.py", line 17, in <module>
safe_division_c(1, 10**500, True, False)
TypeError: safe_division_c() takes 2 positional arguments but 4 were given
파이썬에서도 가변인수를 사용할 수 있고, 잘 사용하면 훨씬 명확하고 읽기 쉬운 코드를 작성할 수 있습니다! :)
'Computer Engineering > Python' 카테고리의 다른 글
파이썬에서 효율적으로 메모리 관리하는 방법 - del, 제너레이터, 가비지컬렉션 (0) | 2023.07.13 |
---|---|
[Pythonic한 코드 작성하기] 파이썬의 자식 프로세스 관리 모듈, subprocess (0) | 2021.04.21 |
[Pythonic한 코드 작성하기] 리스트 컴프리헨션 (list comprehension) (0) | 2021.02.03 |
파이썬에서 Generator란? (0) | 2021.01.27 |
파이썬에서 Generator란? (feat. yield 함수) (0) | 2021.01.09 |
댓글
이 글 공유하기
다른 글
-
파이썬에서 효율적으로 메모리 관리하는 방법 - del, 제너레이터, 가비지컬렉션
파이썬에서 효율적으로 메모리 관리하는 방법 - del, 제너레이터, 가비지컬렉션
2023.07.13 -
[Pythonic한 코드 작성하기] 파이썬의 자식 프로세스 관리 모듈, subprocess
[Pythonic한 코드 작성하기] 파이썬의 자식 프로세스 관리 모듈, subprocess
2021.04.21 -
[Pythonic한 코드 작성하기] 리스트 컴프리헨션 (list comprehension)
[Pythonic한 코드 작성하기] 리스트 컴프리헨션 (list comprehension)
2021.02.03 -
파이썬에서 Generator란?
파이썬에서 Generator란?
2021.01.27