TIL

TIL.26 함수 매개변수 및 인수

codermun 2020. 11. 3. 17:39
728x90
반응형

# 함수에서 위치 인수와 키워드 인수 사용하기

## 위치 인수와 리스트 언패킹

## 위치 인수(positional argument) : 

아래와 같이 함수에 인수를 순서대로 넣는 방식을 위치 인수라고 한다. 인수의 위치가 정해져있다는 뜻이다.

print(1, 2, 3)

# 우리가 사용하는 흔한 방식

## 위치 인수를 이용해 함수를 만들고 호출해보자.

def aaa (a, b, c):
    print(a)
    print(b)
    print(c)

aaa(1, 2, 3)
::
1
2
3

## 언패킹 사용하기

## 위에서 만든 함수에서 언패킹을 사용해보자

## 아래와 같이 리스트 또는 튜플 앞에 *(애스터리스크)를 붙여 함수에 넣어주면 된다. (함수를 호출 할때)

# 함수(*리스트)

# 함수(*튜플)

def aaa (a, b, c):
    print(a)
    print(b)
    print(c)
    
x = [10, 20, 30]
# aaa(x) ## error  
# aaa([10, 20, 30]) ## error

aaa(*x)
aaa(*[10, 20, 30]) 
::
10
20
30

# aaa(x) ## error  
# aaa([10, 20, 30]) ## error

## 이때 함수의 매개변수 개수와 리스트의 요소 개수가 같아야 한다. 다를 경우 함수를 호출 할 수 없다.

# TypeError: aaa() missing 2 required positional arguments: 'b' and 'c' //

2개의 매개변수가 더 필요하다는 내용의 에러가 뜸을 확인할 수 있다.


## 위치 인수와 리스트 언패킹 기능을 이용해 인수의 개수가 정해지지 않은 가변 인수에 사용 할 수 있다.

## 가변 인수 (variable argument) : 인수의 개수가 정해지지 않은, 인수의 개수를 제한하지 않는, 방식을 가변 인수라 한다.

## 가변 인수는 인수를 1개, 10개 또는 아무것도 넣지 않을 수 도 있다.

매개 변수 앞에 *(애스터리스크)를 사용하면 된다. (함수를 생성할때)

# def 함수이름(*매개변수):

#     코드

def bbb (*args):
    for arg in args:
        print(arg)

bbb(10, 20, 30, 40, 50)
::
10
20
30
40
50

y = [10, 20, 30]
bbb(y) 
::
[10, 20, 30]

bbb(*y)
::
10
20
30

x = [10]
bbb(x)
::
[10]
bbb(*x)
::
10

 

## 함수를 만들때 매개변수의 이름은 관례적으로 arguments 를 줄인 , "args"를 사용한다.

## 이 (args)는 튜플 형식으로 for 문으로 반복할 수 있다.


## 고정 인수와 가변 인수 함께 사용하기

def ccc (a, *args):
    print(a)
    print(args)

ccc(1)
::
1
() # args에 인수를 입력하지 않았다.

ccc (10, 100, 200, 300)
::
10
(100, 200, 300)

## 여기서 ccc(*args, a) 와 같이 가변인수는 고정 인수 보다 앞쪽에 위치하면 안된다.

## 반드시 매개변수 순서에서 *args는 가장 뒤쪽에 있어야 한다.


## 키워드 인수 사용하기

## 사용자의 개인정보를 출력해주는 함수를 예로 들어보자.

def personal_info(name, age, address):
    print('이름: ', name)
    print('나이: ', age)
    print('주소: ', address)

## 내가 만든 함수에서는 매개변수 1 ,2, 3이 무엇인지 알고 있어, 함수를 호출 할 경우 인수에 (이름, 나이, 주소)라는 인수를 넣어 함수를 호출하였지만

## 매번 함수 생성 당시 각각의 인수가 무슨 용도인지 직접 만든사람이 아니면, 알기가 어려웠다.

## personal_info(30, 홍길동, 서울)을 입력할 경우 이름은 30이 되고, 나이는 홍길동이 된다.

## 이러한 불편을 줄이기 위해 파이썬에서는 "키워드 인수"를 제공한다.

## 함수(키워드=값)

personal_info(name='홍길동', address='서울', age=30)
::
이름:  홍길동
나이:  30
주소:  서울

## 키워드 인수는 함수 호출 시 사용한다.

## 위 처럼 이름, 나이, 주소 의 순서가 아니여도 키워드 인수로 인해 해당하는 값이 정상적으로 들어가게 된다.

# 추가, 여지껏 키워드 인수는 많이 사용해온 것을 알 수 있다.

print(123sep=':'end=''## 매번 사용하던 sep, end 도 키워드 인수이다. 


## 키워드 인수와 딕셔너리 언패킹 사용하기

## 딕셔너리를 사용한 키워드 인수 값 넣기

## 함수 호출 시 딕셔너리 앞에 ** (애스터리스크)2개를 붙혀주면 된다.

## 함수(**딕셔너리)

def personal_info(name, age, address):
    print('이름: ', name)
    print('나이: ', age)
    print('주소: ', address)

x = {'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'} 
personal_info(**x)
::
이름:  홍길동
나이:  30
주소:  서울시 용산구 이촌동

personal_info(**{'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'})
::
이름:  홍길동
나이:  30
주소:  서울시 용산구 이촌동

## 딕셔너리 변수 또는 딕셔너리 앞에 바로 **를 붙혀도 동작한다.

## 딕셔너리를 이용해 키워드 인수를 사용하기 위해선 몇가지 조건이 필요하다.

# 1. 딕셔너리 언패킹 사용시 함수의 매개변수 이름과 딕셔너리의 키 이름이 같아야 한다. 

# 2. 매개변수의 개수와 딕셔너리 키의 개수도 같아야 한다, 이름 또는 개수가가 다르면 함수를 호출 할 수 없다.

# 3. 딕셔너리 키는 반드시 "문자열" 형태여야 한다.

## **(애스터리스크)를 2번 사용하는 이유

## 가장 큰 이유는 딕셔너리가 키 - 값 쌍의 형태로 값이 저장되어 있기 때문이다.

def personal_info(name, age, address):
    print('이름: ', name)
    print('나이: ', age)
    print('주소: ', address)

x = {'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'} 
personal_info(*x)
::
이름:::  name
나이:  age
주소:  address

personal_info(**x)
::
이름:  홍길동
나이:  30
주소:  서울시 용산구 이촌동

## 애스터리스크를 1개만 사용할 경우  위와 같이 x의 "키" 값만 출력된다.

## 즉, 딕셔너리의 키 값만을 출력하고 싶다면 애스터리스크를 1번만 사용하면 된다.

(딕셔너리를 1번 언패킹하면 키가 사용된다는 뜻)

## 애스터리스크를 2번 사용하여 값을 사용하도록 만들어 준다.(딕셔너리 2번 언패킹하면 값이 사용된다는 뜻)


## 키워드 인수를 사용하는 가변 인수 함수 만들기

## 매개변수 앞에 ** 2개를 사용하면 된다.

def 함수이름(**매개변수):

#     코드

def aaa (**kwargs):
    for kw, arg in kwargs.items():
        print(kw, ':', arg)

 

## 매개 변수 이름은 관례적으로 keyword arguments를 줄여 kwargs를 사용한다.

## 특히 이 kwargus는 딕셔너리로 for 반복문으로 반복할 수 있다.

def aaa (**kwargs):
    for kw, arg in kwargs.items():
        print(kw, ':', arg)
        
aaa(name='홍길동')
::
name : 홍길동

aaa(name='홍길동', age=30, address='서울시 용산구 이촌동')
aaa(**x)
::
name : 홍길동
age : 30
address : 서울시 용산구 이촌동

## 인수를 직접 넣어도 가능하며 딕셔너리 언패킹을 사용해도 된다.

## 인수와 딕서녀리 언패킹을 사용해도 값이 같음으로 

# 딕셔너러 x ={'name': '홍길동'} 일때는 ->

   add(**x) == add(name='홍길동')

# 딕셔너러 x ={'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'} 일때는 -> 

   add(**x) == add(name='홍길동', age=30, address='서울시 용산구 이촌동')으로 서로 같다는 걸 알 수 있다.

# 이처럼 함수를 만들 때 def personal_info(**kwargs):와 같이 매개변수에 **를 붙여주면 키워드 인수를 사용하는 가변 인수 함수를 만들 수 있다.

# 그리고 이런 함수를 호출할 때는 키워드와 인수를 각각 넣거나 딕셔너리 언패킹을 사용하면 된다.

## 보통 **kwargs를 사용한 가변 인수 함수는 아래와 같이 함수 안에 특정 키가 있는지 확인 뒤 해당 기능을 만든다.

 

def personal_info(**kwargs):
    if 'name' in kwargs:    # in으로 딕셔너리 안에 특정 키가 있는지 확인
        print('이름: ', kwargs['name'])
    if 'age' in kwargs:
        print('나이: ', kwargs['age'])
    if 'address' in kwargs:
        print('주소: ', kwargs['address'])

## 고정 인수와 가변인수(키워드 인수)를 함께 사용하기

def personal_info_1(name, **kwargs):
    print(name)
    print(kwargs)

personal_info_1('홍길동')
::
홍길동
{}          # 키워드 인수 아무것도 넣지 않음

personal_info_1('문타리', age=30, address='서울시 용산구 이촌동')
::
문타리
{'age': 30, 'address': '서울시 용산구 이촌동'}.

personal_info_1(**{'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'})
::
홍길동       # 앞에 문타리, 를 넣어줄 경우 고정인수 충돌
{'age': 30, 'address': '서울시 용산구 이촌동'}

## 위치 인수와 키워드 인수 함께 사용하기

def custom_print(*args, **kwargs):
    print(*args, **kwargs)

custom_print(1, 2, 3, sep=':', end='')
::
1:2:3

## 이때 def custom_print(**kwargs, *args):처럼 **kwargs가 *args보다 앞쪽에 오면 안 된다.

## 매개변수 순서에서 **kwargs는 반드시 가장 뒤쪽에 와야 한다.

## 특히 고정 매개변수와 *args, **kwargs를 함께 사용한다면 

## def custom_print(a, b, *args, **kwargs):처럼 매개변수는 고정 매개변수, *args, **kwargs 순으로 지정해야 한다.


## 매개변수에 초깃값 지정하기

## 함수를 호출 할때 항상 인수를 넣어 값을 전달하였다. 그렇다면 인수를 생략 할 수는 없을까?

## 이를 위해 함수를 정의할때 매개변수에 초깃값을 지정해주면 된다.

## 초깃값을 기본값으로 생각하여도 문제가 없을 것 같다. 

    왜냐하면 초깃값은 말그대로 초깃값으로 얼마든지 덮어씌워질 수 있기 때문이다.

def personal_info(name, age, address='비공개'):
    print('이름: ', name)
    print('나이: ', age)
    print('주소: ', address)

personal_info('홍길동', 30)
::
이름:  홍길동
나이:  30
주소:  비공개

personal_info('홍길동', 30, '서울시 용산구 이촌동')
::
이름:  홍길동
나이:  30
주소:  서울시 용산구 이촌동

## 초기값이 지정된 매개변수의 위치

def personal_info(name, address='비공개', age): ## error
    print('이름: ', name) 
    print('나이: ', age)
    print('주소: ', address)

## 매개변수에 초깃값을 지정해줄때는 순서 및 위치가 굉장히 중요하다.

## 위 코드에서 ('홍길동', 30)으로 호출 하였을때 30이 어디로 들어가야하는지 알 수 없기 때문이다.

## 즉, 초깃값이 지정된 매개변수는 아래와 같이 뒤쪽으로 몰아주면 된다.

def personal_info(name, age, address='비공개'):

def personal_info(name, age=0, address='비공개'):

def personal_info(name='비공개', age=0, address='비공개'):

# 참고// def personal_info(name='비공개', age=0, address='비공개'):와 같이 

  모든 매개변수에 초깃값을 지정하면 personal_info()처럼 인수를 넣지 않고 호출할 수 있다.

## 이처럼 함수 생성에서 사용되는 위치 인수, 키워드 인수에서는 

### 리스트(튜플) 이면 ( + 위치인수) ==> * (에스터리스크 1개)

### 딕셔너리 이면 ( + 키워드인수)==> ** (에스터리스크 2개)를 사용한다는 점만 기억하자!

### *args <==> 호출 시 인수 개수가 다양한 경우 (생성시 매개변수)

### **kwargs <==> 키워드 인수로 호출이 이루어졌을 경우 (생성시 매개변수)

728x90
반응형