Channi Studies

[python] *args 과 **kwargs 본문

python

[python] *args 과 **kwargs

Chan Lee 2023. 10. 10. 02:05

*args (arguments)

Python 코드를 작성할 때, 함수에 인자(arguments)가 몇개 입력될 지 모르는 경우가 생긴다.

예를 들어, 가족 구성원을 입력하면 그대로 출력하는 함수가 있다면, 개인별로 가족의 구성원 수는 다르기 때문에 인자가 총 몇개 입력될지는 알 수 없다.

세계의 모든 가족이 4명으로만 이루어져 있다면, 우리가 알던 것 처럼 다음과 같이 함수를 짤 수 있다.

def family(dad, mom, sibling, me):
	print(dad, mom, sibling, me)
   
family("김범수", "이소라", "박효신", "장범준")		
# output: 김범수 이소라 박효신 장범준

하지만 당연히 세상의 모든 가족 구성원은 수가 다르고, 이럴 경우 *args를 사용하면 된다.

 

*args의 args는 arguments를 줄인 것이다.

args에 특별한 기능이 있는 것은 아니고, 주로 사용되는 이름이라고 생각하면 된다.

다시 말해, *args로 쓰든 *name으로 쓰든 *numbers 이후에 형태만 맞춘다면 문제가 없다.

 

*args의 입력 값은 tuple의 형태로 저장된다.

그러므로 단순히 print(args)를 하면, 입력했던 값들이 tuple의 형태로 출력된다.

def numbers(*nums):
    print(nums)

numbers(1, 2, 3, 4)
# output: (1, 2, 3, 4)

 

그러므로, 각각의 입력 값을 따로 처리하고 싶다면, 함수 내에 반복문을 넣으면 된다.

def add_1(*nums):
    for num in nums:
        print(num + 1, end=" ")

add_1(1, 2, 3, 4)
#output: 2 3 4 5

 

이를 활용해서 첫번째 함수를 다시 짜면,

def family(*members):
	for member in members:
    	print(member, end=" ")
        
family("mother", "father", "me")
#output: mother father me

family("mother", "me", "brother", "sister")
#output: mother me brother sister

family("grandmother", "grandfather", "father", "uncle", "sister", "brother", "me")
#output: grandmother grandfather father uncle sister brother me

이렇게 인수의 개수를 모를 때도 활용할 수 있다.

 

입력받은 수를 모두 더해서 출력하는 프로그램을 짜보자면, 다음과 같이 짤 수 있다.

def add(*args):
	result = 0
	for num in args:
    	result += num
	return result

print(add(1, 2, 3))
# output: 6

print(add(300, 100, 30, 3, 500))
# output: 933

 


 

*kwagrs (key word arguments)**

kwargs는 키워드 딕셔너리를 만들어낸다. 

*args 처럼 kwargs 단어 자체에 기능이 있는것은 아니기에, 원하는 글자로 바꿔서 사용해도 된다.

함수를 보면 쉽게 이해할 수 있다.

def calculate(**kwargs):
	print(kwargs)

calculate(add=5, multiply=10, divide=2)
# output: {"add": 5, "multiply": 10, "divide": 2}

 

입력한 키워드와 값으로 딕셔너리를 만들어 내는 것을 볼 수 있다.

방금의 함수를 확장해서 딕셔너리 형태를 활용해 간단한 계산 과정을 하는 함수를 만들 수도 있다

(실제로는 절대 사용 안하겠지만, kwargs를 이해하기에 도움이 된다)

def calculate(num, **kwargs):
    num += kwargs["add"]
    num *= kwargs["multiply"]
    num /= kwargs["divide"]
    print(num)

calculate(3, add=5, multiply=10, divide=2)
# (3 + 5) * 10 / 2 = 40
# output: 40

 


Class에서의 kwargs

kwargs는 class 선언에서도 잘 활용될 수 있다. 

다음 예제를 보자.

class Car:

	def __init__(self, **kw):
    	self.model = kw["model"]	
        self.company = kw["company"]
        self.color = kw["color"]

first_car = Car(company="Hyundai", model="Santafe", color="black")

print(first_car.company, first_car.model, first_car.color)
#output: Hyundai Santafe black

 

클래스를 선언하고 초기화할 때 자주 사용하던 형태가 보인다.

하지만 이는 권장하는 방법이 아니다.

이유를 알아보기 위해 여기서 만약에 keyword중에 하나라도 빼먹는다면 무슨 일이 발생할까?

 

class Car:

	def __init__(self, **kw):
    	self.model = kw["model"]	
        self.company = kw["company"]
        self.color = kw["color"]

first_car = Car(company="Hyundai", model="Santafe")

print(first_car.company, first_car.model, first_car.color)
#KeyError: 'color'

 

KeyError: keyword 오류가 발생한다.

이를 방지하기 위해서는 kw["color"] 말고 다른 방식을 사용할 수 있다.

그것은 get() 메소드이다.

 

class Car:

	def __init__(self, **kw):
   	    self.model = kw.get("model")
	    self.company = kw.get("company")
            self.color = kw.get("color")

first_car = Car(company="Hyundai", model="Santafe")

print(first_car.company, first_car.model, first_car.color)
#output: Hyundai Santafe None

get() 메소드를 사용해서 코드를 작성하면, 키워드를 입력하지 않았을 때, 클래스 초기화 과정에서 오류가 발생하지 않고 대신 None 값이 저장된다.

이것은 선택적 인수가 많은 클래스에서 흔히 사용되는 방법이다.

 

물론, 기본값을 지정해서 초기화하는 방법도 가능하다.

class Car:
	def __init__(self, company="Hyundai",**kw):
            self.model = kw.get("model")	
            self.company = company
            self.color = kw.get("color")

car1 = Car(color="blue", company="Ferrari")
car2 = Car(color="purple", model="GV80")
car3 = Car()

print(car1.color, car1.company, car1.model)
# output: blue Ferrari None

print(car2.color, car2.company, car2.model)
# output: purple Hyundai GV80

print(car3.color, car3.company, car3.model)
# output: None Hyundai None

이렇게 코드를 짜면, self.company 값에 대해서는 kw을 사용하지 않고, 우리가 알던 초기화 방법으로 사용할 수도 있다.