본문 바로가기
목차
Python

[Python] asterisk * 사용하기 : unpacking, packing

by ds31x 2023. 7. 30.
728x90
반응형

C언어에서 pointer 연산자인 * (asterisk)는 Python에서 상당히 낯설게 동작한다.

(특히, PEP3132, PEP448 등에서 그 기능이 무지 많아져서... --;;)

 

double asterisk ** (이문서에선 다루지 않으나, variable keyword argument로 사용됨) 와 함께 packing과 unpacking 기능으로 정말 많이 사용되기 때문에 한번은 정리를 해보는게 도움이 된다.

 

크게 function과 관련되어서는 두가지 mode로 동작한다.

  • function을 define 할 때 parameter에서 사용되는 경우 (= function header에서 사용되는 경우) : packing
  • function call에서 argument로 사용되는 경우 : unpacking

이와 유사하지만 조금 색다르게 보이는 경우도 다음과 같이 있다.

  • assignment의 left side에 놓이는 경우 : packing
  • list 를 나타내는 square brackets [ ] 안에 놓이는 경우 : unpacking
  • list 외에 set { }이나 tuple ( ) 안에 놓이는 경우 : unpacking

function definition 에서의 활용은 다음 URL에서 좀 더 확실히 확인할 것.

2024.02.04 - [Python] - [Python] Parameter 의 종류 - Slash and Asterisk for Function Parameters

 

[Python] Parameter 의 종류 - Slash and Asterisk for Function Parameters

Function의 헤더에서 parameters 를 정의하는데,해당 parameters 중,어떤 것들이 positional parameters 로만 사용가능한지,어떤 것들이 일반적인 parameters로서 positional parameters 또는 keyword parameters 모두 사용가

ds31x.tistory.com


Function's arguments and paraemters

다음 예제는 function header에서 parameter에 사용되는 경우로 packing을 수행하는 예이다.

def test_func(*pack):
  print(type(pack),pack)
  for idx, c in enumerate(pack):
    print(f'{idx:02} : {str(c):>14}')

test_func('사과','바나나','복숭아','자두')
  • test_func에 주어진 복수의 argument들이 pack이라는 이름을 가지는 tuple 객체로 packing 됨을 확인할 수 있음.
  • positional arguments의 순서를 유지하는 immutable sequence type 인 tuple로 묶임.
  • 위와 같은 방법으로 사용되는 경우 관례적으로 *args 라고 parameter를 기재하나, 위 예제에서는 packing을 강조하기 위해 이름을 바꿈. (가급적 관례를 따르기를 권함)
이같은 *args
variable postional argument라고 부르며,
이 후로는 반드시 keyword-only argments 만이 놓이게 됨.

 

결과는 다음과 같음.

<class 'tuple'> ('사과', '바나나', '복숭아', '자두')
00 :             사과
01 :            바나나
02 :            복숭아
03 :             자두

다음은 *를 function call에서의 argument로 사용할 경우의 예임.

unpack = ['사과', '바나나', '복숭아', '자두']

test_func(*unpack) # test_func('사과','바나나','복숭아','자두') 와 동일.
  • *unpack으로 argument를 넘겨주면, unpack list를 unpacking하여 각각의 item들이 arguments로 주어지게 됨.
  • 때문에 앞서 결과와 같은 arguments를 넘겨준 것과 같은 결과를 보임.

만약 다음과 같이 *를 빼고 unpack만을 argument로 넘겨주는 것을 실행해보자.

>>> test_func(unpack)
<class 'tuple'> (['사과', '바나나', '복숭아', '자두'],)
00 : ['사과', '바나나', '복숭아', '자두']
  • list unpack이 통째로 하나의 argument로 주어진다 (unpacking이 일어나지 않음)
  • 때문에 하나의 argument로 처리되고 list unpack에서의 __str__ special method의 반환값에 해당하는 문자열이 출력됨.

다른 경우들.

다음은 assignment의 left side에 놓이는 경우에 대한 예이다.

first, second, *remaining = unpack

print(first)
print(second)
print(remaining)
print(type(remaining))
  • a,b,c=1,2,3 과 같은 다중할당은 left side와 right side의 item의 수가 같아야함.
  • 하지만, 위와 같이 *remaining이 left side에서 사용되면, 나머지 item들을 모두 packing한 list객체 remaining이 됨.
  • 이는 마치 function header에서 *로 시작하는 parameter에 여러 arguments가 packing되는 것과 개념적으로 유사함.

결과는 다음과 같음.

사과
바나나
['복숭아', '자두']
<class 'list'>

list 를 나타내는 square brackets [ ] 안에 놓는 경우에 대한 예는 다음과 같다.

>>> new_list = [ *unpack, *reversed(unpack)]
>>> new_list
['사과', '바나나', '복숭아', '자두', '자두', '복숭아', '바나나', '사과']
  • 위의 code snippet은 unpack list를 역순으로 뒤에 concatenate 시킴.

*을 이용한 unpacking을 활용한 예로서 PEP 448에서 추가된 기능이다.
이전에 위와 같은 처리는 다음과 같이 해야 했음.

new_list = [list(unpack), list(reversed(unpack))]
  • 같은 결과를 얻을 수 있지만, 좀 더 비 효율적으로 알려져 있음.

아래와 같이 timeit 모듈을 통해 확인 가능함.

import timeit
unpack = ['사과', '바나나', '복숭아', '자두']

def test_fn0 ():
  ret = [ *unpack, *reversed(unpack)]
  return ret

print('the case of * :', round(timeit.timeit(test_fn0, number= 1_000_000),4))

def test_fn1 ():
  ret = [list(unpack), list(reversed(unpack))]
  return ret

print('the case of old approach :', round(timeit.timeit(test_fn1, number= 1_000_000),4))
  1. timeit.timeit() 함수는 Python의 timeit 모듈에서 제공하는 성능 측정 함수.
  2. test_fn0는 측정 대상인 함수 object임: 이 함수의 실행 시간을 측정함.
  3. number=1_000_000는 함수를 실행할 횟수를 지정. 기본값은 1,000,000회.
  4. 결과값으로 함수를 지정된 횟수만큼 실행하는 데 걸린 총 시간(second 단위)을 반환

이를 많이 사용하는 경우
다음과 같이 맨 앞의 item을 맨 뒤로 보내고, 나머지 item들을 하나씩 앞으로 보내는 처리 등을 할 때 매우 유용하다.

>>> new_list = [*unpack[1:],unpack[0]]
>>> new_list
['바나나', '복숭아', '자두', '사과']

또는 두 list의 union을 구할 때에도 다음과 같이 활용가능하다.

u = {*a, *b} # set().union(a,b)

Keyword-only arguments 처리하기.

function header에서 다음과 같이 *를 parameter로 사용할 경우,
특정 parameter 이후로는 positional arguments를 사용하지 못하도록 막을 수 있다.

def test_fn( a, *, key0=None):
  """ a 파라메터까지만 positional argument로 할당가능하고, 
  * 이후에 있는 key0는 keyword argument로만 사용가능함.
  """
  print(f'a={a}')
  print(f'key0={key0}')

test_fn(a)
test_fn(a,1)
  • * 이후로는 무조건 keyword argument로만 사용가능해짐.

double asterisk 사용법

2025.07.16 - [Python] - [Py] double asterisk 사용법-packing and unpacking

 

[Py] double asterisk 사용법-packing and unpacking

Python의 ** (double asterisk) 연산자는 keyword argument와 dictionary unpacking 에 사용됨.파이썬에서 ** (더블 애스터리스크, 또는 더블 스타) 연산자는 다음의 역할을 수행함:dict 객체 관련 연산function 정의와

ds31x.tistory.com


같이 보면 좋은 자료들

https://gist.github.com/dsaint31x/d139f4a7dac95a301bc6a06f3bd12755

 

py_asterisk_ex.ipynb

py_asterisk_ex.ipynb. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

2024.02.04 - [Python] - [Python] Parameter 의 종류 - Slash and Asterisk for Function Parameters

 

[Python] Parameter 의 종류 - Slash and Asterisk for Function Parameters

Function의 헤더에서 parameters 를 정의하는데,해당 parameters 중,어떤 것들이 positional parameters 로만 사용가능한지,어떤 것들이 일반적인 parameters로서 positional parameters 또는 keyword parameters 모두 사용가

ds31x.tistory.com


 

728x90