함수 인자, Packing, Unpacking!

Why bolging?

오늘 병민 멘토님에게 라이브로 코드리뷰를 받았다. 만든 기능이 대단하지 않지만 병민 멘토님께서 팀원들의 코드를 세세하게 리뷰 해주셨다. 그 과정에서 나온 토픽인 패킹과 언패킹에 대해서 블로그 해보려고 한다.

위치 인자 vs 키워드 인자

위치 인자란? 인자와 매개변수에 위치를 일치시키는 인자.
키워드 인자란? 매개변수에 이름으로 일치시키는 인자.
어떤 방식으로 인자를 함수에 보내도 상관은 없지만, 위치인자는 항상 키워드 인자보다 먼저 작성되어야 한다.

# 위치인자
func('py', 'thon')

# 키워드 인자
func(b='thon', a='py')

# 가능
func('py', b='thon')

#불가능
func(a='py', 'thon') # SyntaxError

매개변수 기본값

함수를 정의할때 매개변수의 기본값을 지정할 수 있다.
매개변수의 기본값을 지정하는 경우에은 함수를 사용할때 인자를 보내지않는다면 미리 지정한 기본값을 사용하여 함수를 실행합니다.

def func(a, b=3):
     return a + b

print(func(10, 10)) 
# 20 출력
print(func(10)) 
# 13출력

위 함수는 함수 안에 매개변수 b의 값이 기본값 3을 가지고 있습니다. 인자를 모두 넘겨준다면 기본값을 무시한 결과를 출력하고, (10+10)

만약 매개변수에 매칭되는 인자가 없다면 기본값을 사용하여 연산합니다.

Packing

패킹(packing)은 인자로 받은 여러개의 값을 하나의 객체로 합쳐서 받을 수 있도록 합니다. 위치인자 패킹* 한개를 매개변수 앞에 붙임으로 사용합니다.

def func(*args):
      print(args)
      print(type(args))
      
func(1, 2, 3, 4, 5, 6, 'a', 'b')
-------------------출력-------------------
(1, 2, 3, 4, 5, 6, 'a', 'b')
<class 'tuple'>

활용! 패킹을 통해 받은 모든 숫자들의 합 구하기

def sum_all(*numbers):
      result = 0
      for number in numbers:
           result += number
      return result

print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5, 6)) # 21

활용!패킹을 통해 반드시 받아야하는 매개변수와 여러개를 받을수있는 매개변수를 구분해서 작성

def print_family_name(father, mother, *sibling):
      print("아버지 :", father)
      print("어머니 :", mother)
      if sibling:
           print("호적 메이트..")
           for name in sibling:
                 print(name)

print_family_name("홍길동", '심사임당', '김태희', '윤아')
---------------출력---------------
아버지 : 홍길동
어머니 : 심사임당
호적 메이트..
김태희
윤아

위치인자가 패킹하는 매개변수를 만나면 그 이후에 위치인자가 몇개이던지, tuple로 하나의 객체가되어서 관리됩니다.


키워드 인자에 패킹은 **을 통해 작성할 수 있습니다.

def kwpacking(**kwargs):
     print(kwargs)
     print(type(kwargs)

kwpacking(a=1, b=2, c=3)

-----------------결과--------------
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>

활용! print_family_name함수에 호적메이트들에 사회적명칭을 출력해보자.

def print_family_name(father, mother, **sibling):
      print("아버지 :", father)
      print("어머니 :", mother)
      if sibling:
           print("호적 메이트..")
           for title, name in sibling.items():
                 print('{} : {}'.format(title, name))

print_family_name("홍길동", '심사임당', 누나='김태희', 여동생='윤아')
--------------------출력--------------------
아버지 : 홍길동
어머니 : 심사임당
호적 메이트..
누나 : 김태희
여동생 : 윤아

활용! 위치 인자와 키워드 인자 packing을 동시에 사용할 수 있습니다.

def print_family_name(*parents, **sibling):
      print("아버지 :", parents[0])
      print("어머니 :", parents[1])
      if sibling:
           print("호적 메이트..")
           for title, name in sibling.items():
                 print('{} : {}'.format(title, name))

print_family_name("홍길동", '심사임당', 누나='김태희', 여동생='윤아')
---------------------출력----------------
아버지 : 홍길동
어머니 : 심사임당
호적 메이트..
누나 : 김태희
여동생 : 윤아

Unpacking

언패킹(unpacking)은 여러개의 객체를 포함하고 있는 하나의 객체를 풀어줍니다.

함수에서 언패킹을 할때는, 매개변수에서 *을 붙이는게 아니라 인자 앞에 *을 붙여서 사용합니다.

동일하게 위치인자를 unpacking 하는 경우는 *를, 키워드인자를 unpacking하는 경우 **를 사용합니다.

def sum(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
sum(numbers) # error

print(sum(*numbers)) # 출력 : 6
# 1. sum(*numbers)
# 2. sum(*[1, 2, 3])
# 3. sum(1, 2, 3)

unpacking은 함수를 호출할때 인자를 해체하는 개념이기 때문에, 해채된 결과가 함수의 매개변수에 갯수와 다르다면 에러가 발생합니다.

sum(*[1, 2, 3, 4])
------------출력-------------
TypeError: sum() takes 3 positional arguments but 4 were given

위치인자를 qunpacking할때는 위에 예에서는 list타입이였지만, Container객체라면 다 가능합니다.

sum(*'abc') # 'abc'
sum(*(4, 5, 6)) # 15
sum(*{'가', '나', '다'}) # '나다가'
sum(*{'치킨': 3, '피자': 12, '음료수': 10}) # '치킨피자음료수'

set타입과 dict타입은 순서정보를 가지고 있지 않기 때문에 결과가 다를 수 있습니다.

동일한 방식으로 키워드인자로 unpacking할 수 있습니다. unpacking하기 위해선 인자가 key인자로 구성되어 있는 mapping타입, 즉 dict가 필요합니다.

def cal(first, op, second):
    if op == '+':
        return first + second
    if op == '/':
        return first / second
    if op == '-':
        return first - second
    if op == '*':
        return first * second

prob = {
  'first': 12,
  'second': 34,
  'op': '*'
}
-------------출력------------
#1. cal(**prob)
#2. cal(prob = {'first': 12,'second': 34,'op': '*'})
#3. cal(first=12, second=34, op='*')

cal(**prob) # 결과 : 408

위치인자의 unpacking처럼 unpacking되는 인자는 매개변수의 키워드 매개변수와 일치해야합니다.

만약 비어있는 인자를 unpacking를 하면 무시합니다. 이러한 특성이 있기 때문에 함수의 packingunpacking을 이용하여, 다음과 같이 어떠한 함수에도 반응하는 함수를 작성할 수 있습니다.

함수와 함수에 인자들을 받아서 시작전 알림과 함께 함수를 실행시켜주는 함수입니다.
활용!

def start(func, *args, **kwargs):
    print("함수를 시작합니다.")
    return func(*args, **kwargs)
   
start(print, '안녕하세요', '파이썬 꿀잼!', sep='~~ ')
------------------출력-------------------
함수를 시작합니다.
안녕하세요~~ 파이썬 꿀잼!

활용!

def sum_a_b(a, b):
     return a + b

result = start(sum_a_b, 1, 2) # 함수를 시작합니다.
print(result) # 3

After blogging...

분명 wecode가 시작하기전에 파이썬 기본함수는 다 익히고 시작했다 생각했는데 오늘 다시 제대로 파이썬을 공부하면서 아직 부족한 점이 많다는 것을 느꼇다. 또한 데코레이터 작동원리를 위해 하루 반나절을 유튜브와 구글링으로 하루를 보낸적도 있었다. packing과 unpacking에 대해 이해도가 있었다면 조금 더 빨리 이해할 수 있었는데 그때 이해하지 못했던 퍼즐이 오늘 맞춰졌다.

좋은 웹페이지 즐겨찾기