본문 바로가기

더 나은 엔지니어가 되기 위해/파이썬을 파이썬스럽게

파이썬 Asterisk(*)에 대해서

머신러닝을 위한 파이썬 워밍업을 수강하던 와중에, Asterisk(*) 에 관해, 새롭게 알게된게 있어서 적어본다.

파이썬 오픈소스들 보다보면, 함수 정의할 때 인자에 *args 식으로 인자가 정의되어있는 식으로 *을 종종본다.
사실 이전 포스트에서도 적었듯, 이 쓰임새를 아예 몰랐던 건 아닌데, 이번 강좌를 통해 더 깊이 알게되었다.

사실, Asterisk라고 부르는 것도 처음알게 되었다.

용도와 쓰임새를 하나씩 다시 복습해보자.

1. * 인자는 함수 내에서 튜플이다.

가장 직관적인 예는 다음과 같다.

def a(*args):
    print(type(args))
    print(args)
a(1,2,3,4)

# output:
# <class 'tuple'>
# (1, 2, 3, 4)

보다시피 튜플이다. 따라서, 내부에서 list처럼 mutable 하게 조작하려면 list(args) 식으로 리스트로 변환시켜야 한다.

2. * 은 Unpacking 역할을 한다.

* 이 다음과 같이 등장할 때가 있다. 이를 관찰해보자.

def a(*args):
    #print(type(*args))
    print(*args)
a(1,2,3,4)

# output:
# 1 2 3 4

이전과 다르게 args 가 아니라, *args 를 출력했다. 뭐가 다른가?

출력을 보면, 튜플이 아니다. 양쪽 괄호가 없어졌다. 괄호를 하나 벗겨낸 셈이다.

이게 무슨 type 인지 알아보려고 type(*args) 을 출력해봤지만, 오류가 나서 확인할 수 없었다.

아무튼 간, 핵심은 괄호를 벗겨낸다는 것이다. 튜플만 그럴까?

b = [1,2,3,4]
print(*b)

# output:
# 1 2 3 4

리스트도 된다. 양 옆에 [] 이 없어졌다.

* 을 앞에 붙여주면 양 옆에 괄호를 벗겨내는, Unpacking 역할을 하는 것을 알 수 있다.

다음 예시를 통해 확실히 알 수 있다.

a = ((1,2), (3,4))
b = [[1,2,3,4]]
print(*a)
print(*b)

# output:
(1, 2) (3, 4)
[1, 2, 3, 4]

3. 이거 언제 써먹을까?

솔직히 써먹을 일 없을 것 같은데, zip() 쓸 때 엄청 써먹더라 (써먹어야 하드라...)

가장 쉽고 대표적인 예로, 다수의 벡터(리스트)를 입력받아, 다 더해서 내보내는 함수를 짠다고 생각해보자.

def vector_addition(*vector_variables):
    return [sum(i) for i in zip(vector_variables)]

vector_addition([1, 3], [2, 4], [6, 7])

위와 같이 하면 제대로 작동할 것 같은데, 돌리면 다음과 같은 에러가 뜬다.

TypeError: unsupported operand type(s) for +: 'int' and 'list'

이유는, vector_variables = ([1, 3], [2, 4], [6, 7]) 로 tuple 형태로 되서 들어올텐데 zip() 은 이 형식을 지원안한다. zip() 안에 넣어주려면, 이를 unpacking 해줘야 한다.

따라서, zip(vector_variables) 이 아니라, zip(*vector_variables) 로 해줘야 잘 돌아간다.

# ouptut:
[9, 14]