https://wikidocs.net/22801



packing, unpacking

print함수는 출력하고자하는 객체가 몇개던지, 즉 몇개의 인자를 받던지 상관하지 않고 출력해줍니다.

print("가나다 abc 123")
print("가나다", "abc 123")
print("가나다", "abc", "123")

출력결과

가나다 abc 123
가나다 abc 123
가나다 abc 123

이런 경우처럼 함수가 받을 인자의 갯수를 유연하게 지정할 수 있다면 보다 유연하게 코드를 작성할 수 있습니다.

파이썬은 이런 경우를 지원하기 위해 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'>

이러한 packing을 통해 받은 모든 숫자들의 합을 구하는 연산도 구할 수 있습니다. 몇개든 상관없이 가능합니다.

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

packing을 이용해서 반드시 받아야하는 매개변수와 여러개를 받을수있는 매개변수를 구분해서 작성할 수 있습니다.

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

packing과 반대되는 개념인 unpacking이라는 개념이 있습니다.

packing은 여러개의 객체를 하나의 객체로 합쳐주었습니다. 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, 2, 3]을 인자로 보낼때, *을 붙이면 unpacking이 발생합니다.

unpacking은 아래와 같은 순서로 변경되어 실행됩니다.

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

위치인자를 unpacking할때는 위에 예에서는 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': '*'
}

cal(**prob) # 결과 : 408

위 예제에 키워드 인자의 unpacking은 다음과 같이 작동합니다.

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

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

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

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

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


+ Recent posts