TIL #27 Python - Function의 여러가지 가변 인수

채록·2021년 1월 13일
0

Python & Django

목록 보기
1/34
post-thumbnail

블로깅 과제로 몇가지 문제에 대해 에러 요인을 파악하고, 고치고 어떤식으로 호출되는 지에 대해 알아보았다.


I. 가변 인수 / 가변키워드 인수

1. 가변 인수

가변 인수 = variable length arguments
표현 = *args (중요한 것은 한개의 *이다. *뒤에 다른말을 써도 된다.)
임의의 복수 갯수의 인자를 사용자에게 입력받아서 사용할 때 쓰인다
--> 여러개의 인자를 받은 경우, 함수 내부에서는 튜플로 받은 것처럼 인식한다.


2. 가변키워드 인수

가변 키워드 인수 = variable length keyword arguments
표현 = **kwargs (중요한 것은 두개의 **이다.)
키워드로 이루어진 임의의 복수 갯수의 인자를 받는다.




I. default / non-default value

default value = 함수를 지정할때 값이 지정된 parameter



1. Why? non-default > default

앞서 작성한 TIL#34-2를 통해 non-default 값을 default value 보다 앞서 지정해주면 error가 발생하는 걸 확인할 수 있었다.
다시한번 코드를 살펴보면

def love_you(my_name='딸', your_name):
  print(f'{my_name} loves {your_name}')
love_you('엄마')
->
  File "main.py", line 1
    def love_you(my_name='딸', your_name):
                 ^
SyntaxError: non-default argument follows default argument

원인 파악중.. 1

위의 코드로 작성하면 parameter 값인 your_name도 my_name의 defalult value로 인식하나? 싶어서 다음과 같이 코드를 작성해 보았다.

def love_you(your_name, my_name='딸', '아들'):
  print(f'{my_name} loves {your_name}')
love_you('엄마')

->
  File "main.py", line 1
    def love_you(your_name, my_name='딸', '아들'):
                                         ^
SyntaxError: invalid syntax

내심 "딸, 아들 loves 엄마" 라고 출력될줄 알았다;; (영문법 파괴는 무시)

원인 파악중.. 2

눈으로 확인은 못하지만 "함수를 호출할때 입력한 값이 지정된 함수의 parameter에 앞에서부터 순차적으로 들어가는데, 처음으로 마주한 parameter가 이미 값이 지정된 default value를 갖고 있으므로 인간으로 치면 인지부조화 가 일어나나?" 라고 생각해 보았다.
이를 확인하려면... 나처럼 이런 생각을 하는 사람들이 얼마나 있는지 구글링 해봐야 할것 같다.

Googling : Stackoverflow

All required parameters must be placed before any default arguments. Simply because they are mandatory, whereas default arguments are not. Syntactically, it would be impossible for the interpreter to decide which values match which arguments if mixed modes were allowed.
라고 한다!
non-default value는 값을 필수적으로 받아야 하지만 이미 값이 지정된 default value는 그렇지 않다. 또한, 그런 상황이 왔을때 어떤 value와 어떤 argument가 부합하는 지에 대한 흐름에서 이런 필수적인 상황을 방해할 수 없다!

라고 한다.
내 생각이 맞는듯 하다! 인지부조화 적인 상황을 용납하지 않는다!



2. parameter 갯수 != argument 갯수 ?

직접 코드를 짜서 이해해보자

1) 2개의 non-default / 1개의 default + 1개의 argument

def love_you(your_name, how, my_name='딸'):
  print(f'{my_name} loves {your_name} {how}')
love_you('엄마')

->
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    love_you('엄마')
TypeError: love_you() missing 1 required positional argument: 'how'

how 에 대한 argument가 없다고 한다.

2) 2개의 non-default / 1개의 default + 3개의 argument

def love_you(your_name, how, my_name='딸'):
  print(f'{my_name} loves {your_name} {how}')
love_you('엄마', '아빠', '진짜로!')

->
진짜로! loves 엄마 아빠

이걸 보면..

  • argument는 차례로 지정 되었다. (default인 my_name 까지)
    your_name = 엄마
    how = 아빠
    my_name = 진짜로!
  • 새로 지정된 value대로 출력 되었다.

3) 결론

argument의 갯수가 많아 defualt value로 지정된 것 까지 횟수에 포함될때, default value는 새로 지정될 수 있다.




II. 문제1 : 위치 인수와 가변 인수

위치 인수 = positional arguments
가변 인수 = variable length arguments

가변 인수 ?
가변인수는 임의 갯수의 인자를 뜻한다.


1. 문제 발생


1) 문제의 코드

def func_param_with_var_args(name, *args, age):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)

func_param_with_var_args("정우성", "01012341234", "seoul", 20)

2) 문제의 출력 결과

Traceback (most recent call last):
  File "main.py", line 6, in <module>
    func_param_with_var_args("정우성", "01012341234", "seoul", 20)
TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'

함수가 1개의 keyword만 허락하는 argument에 대한 value를 놓쳤다고 말하고 있다.



2. 문제점 파악


1) 원인 파악하기 (내 생각)

가변 인수는 갯수가 가변적인 인자라는 뜻이다. 때문에 이 인자는 갯수가 2개가 될수도 있고, 3개가 될수도 있다.
때문에 프로그램은 이런 가변적인 상황을 스스로 파악하기가 어려울 것이다!

2) 해결책 고안

이러한 상황에 대해 나와 프로그램 사이의 암묵적인 룰을 정해야 할 것이다.
따라서 위치 인수와 가변 인수를 같이 사용할 때 가변 인수를 항상 마지막에 입력해야 한다고 생각한다.



3. 해결책 적용


1) 적용 코드

def func_param_with_var_args(name, age, *args):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)

func_param_with_var_args("정우성", 20, "01012341234", "seoul")

2) 출력 결과

name=정우성
args=('01012341234', 'seoul')
age=20


4. 문제 정리

함수를 지정 할때 가변 인수를 위치 인수보다 뒤에 위치시켜야 한다
+) 가변 인수(variable length argument)도 큰 의미로는 positional argument라고 생각하면 함수를 호출할때 순서를 이해할 수 있다.




III. 문제2 : 가변 키워드 인수의 위치

가변 키워드 인수 = variable length keyword arguments

가변 키워드 인수 ?
임의 갯수의 키워드 인자를 받는 것


1. 문제 발생


1) 문제의 코드

def func_param_with_kwargs(name, age, **kwargs, address=0):
    print("name=",end=""), print(name)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")

2) 문제의 출력 결과

  File "main.py", line 1
    def func_param_with_kwargs(name, age, **kwargs, address=0):
                                                    ^
SyntaxError: invalid syntax

유효하지 않은 syntax라고 말한다.

syntax / 구문 ?
프로그래밍 언어에서 프로그램의 모습, 형태, 구조가 어떻게 보이는지에 대해 정의하는 것



2. 문제점 파악


1) 원인 파악하기 (내생각)

위의 문제와 같은 상황으로 보인다. 가변키워드인수가 제일 뒤에 위치해 있지 않아 생긴 문제로 보인다. 위의 문제에서 가변인수는 위치 인수보다 뒤에 위치해야 한다라는 것을 알수 있었다면 이 문제에서는 가변 키워드 인수는 키워드인수 모두의 뒤에 위치해야 한다라는 것을 알수 있을 것 같다.

2) 해결책 제시

위의 문제해서 사용한 방법처럼 키워드인수와 가변키워드 인수의 위치를 바꿔준다



3. 해결책 적용


1) 적용 코드

def func_param_with_kwargs(name, age, address=0, **kwargs):
    print("name=",end=""), print(name)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")

2) 출력 결과

name=정우성
age=20
kwargs={'mobile': '01012341234'}
address=seoul


4. 문제 정리

함수를 지정할 때 가변 인수는 항상 제일 뒤에 위치해야 한다.



5. 추가로 알게 된 것

  1. 키워드 인수를 사용해 함수를 지정할때 default value를 지정하여도 (함수를 지정할 때 address=0 으로 default value 줌), 함수를 호출할 때 default value에 해당하는 argument를 keyword argument로써 새로 지정해 주면 새로 지정된 값으로 출력된다. 는 것이다. (address="seoul" 라고 하여 호출했더니 seoul로 출력되었다.)
  2. 함수를 호출할때 argument의 우선순위는 positional > keyword 이며, positional > variable length 이다.
  3. 함수를 호출할때 argument의 우선순위는 keyword와 variable length keyword가 동등하다

3) keyword와 variable length keyword의 위치

다음의 예제를 통해 이해할 수 있었다.

#1 keyword 가 variable length keyword argument보다 앞에 위치

def func_param_with_kwargs(name, age, address=0, **kwargs):
    print("name=",end=""), print(name)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

func_param_with_kwargs("정우성", "20", address="seoul", mobile="01012341234", hi="hello")

#2 variable length keyword 가 keyword argument보다 앞에 위치

def func_param_with_kwargs(name, age, address=0, **kwargs):
    print("name=",end=""), print(name)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

func_param_with_kwargs("정우성", "20", mobile="01012341234", hi="hello", address="seoul")

위 두가지에 대한 출력 결과

name=정우성
age=20
kwargs={'mobile': '01012341234', 'hi': 'hello'}
address=seoul



IV. 문제3 : 위치 인수와 가변키워드 인수


1. 문제 발생


1) 문제의 코드

def mixed_params(name="아이유", *args, age, **kwargs, address):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

1) 문제의 출력 결과

  File "main.py", line 1
    def mixed_params(name="아이유", *args, age, **kwargs, address):
                                                       ^
SyntaxError: invalid syntax

유효하지 않은 syntax라고 나온다.



2. 문제점 파악


1) 원인 파악하기 (내 생각)

위 문제와 같은 형태의 오류이다. 위의 문제는 함수를 지정할 때 잘못된 위치로 parameter값을 입력했기 때문에 생긴 문제였다. 그렇다면 이번 문제 역시 함수를 지정할 때 사용된 default / variable length / non-default / variable length keyword / non-default 로 구성된 parameter 혹은 positional / keyword / variable length (keyword) argument 간의 순서에 의한 것임을 유추할 수 있다.
문제점 되게 길다;;

2) 해결책 고안

이건... 순서를 하나하나 정해보는 수밖에 없다. 험난한 여정이 될것.
습득한 지식을 토대로 한단계씩 바꾸면서 계속 출력해보자.

no.1 default값은 non-default보다 뒤에 위치해야 한다.

-> 똑같은 에러 발생

no.2 가변 값은 항상 제일 뒤에 와야 한다.

def mixed_params(age, address, name="아이유", *args, **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

->
Traceback (most recent call last):
  File "main.py", line 8, in <module>
    mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")
TypeError: mixed_params() got multiple values for argument 'address'

address가 너무 많은 value를 갖고 있다고 한다. "정우성", "01012341234", "male"이 모두 지정되었는것 같다.

no3. 그렇다면 여러개의 지정되지 않는 값을 가질수 있는 variable length argument의 위치를 조정

def mixed_params(age, *args, address, name="아이유", **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

->
name=아이유
args=('정우성', '01012341234', 'male')
age=20
kwargs={'mobile': '01012341234'}
address=seoul

오..... 됐나? 싶었는데 왜 아이유가 남자야😮😮😮

no4. default value를 positional argument로 새로 지정하기

def mixed_params(age, name="아이유", *args, address, **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

->
name=정우성
args=('01012341234', 'male')
age=20
kwargs={'mobile': '01012341234'}
address=seoul

됐다 됐어!!!



3. 해결책 적용


1) 적용 코드

def mixed_params(age, name="아이유", *args, address, **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

1-2) 적용 코드 변형 (함수 호출 : 가변키워드 인자와 키워드 인자의 순서

#1. 가변 키워드 인자 > 키워드 인자

def mixed_params(age, name="아이유", *args, address, **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

#2. 가변 키워드 인자 < 키워드 인자

def mixed_params(age, name="아이유", *args, address, **kwargs):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male", address="seoul" ,mobile="01012341234")

2) 출력 결과

name=정우성
args=('01012341234', 'male')
age=20
kwargs={'mobile': '01012341234'}
address=seoul


4. 문제 정리

함수 parameter한테 덤벼보라고 하는 느낌이었다... 다막아 볼테니 어디한번 딜 넣어봐! 하는 느낌? ^__^?

그래도 이번 과제를 통해 함수에 복수의 parameter를 지정하고 이러한 함수를 호출 할때 어떤 우선순위로 코드를 짜야하는가?에 대해 이해할 수 있었다!!!




V. 최종 정리

정보 출처 : https://velog.io/@ifyouseeksoomi/Backend-Python-%EA%B0%80%EB%B3%80-%EC%9D%B8%EC%88%98args%EC%99%80-%ED%82%A4%EC%9B%8C%EB%93%9C-%EC%9D%B8%EC%88%98kwargs
(이분 정말 대단하신것 같다!!!)


def 함수이름 (?):
여기서 ?에 들어가는 것들의 우선순위

  1. 일반 positional 인자
  2. 디폴트 인자 (이미 값을 지정한 인자)
  3. 가변 인자 (*args)
  4. 디폴트가 아닌 Keyword-Only 인자
  5. 디폴트 Keyword-Only 인자
    단 4, 5번은 (4, 4', 5, 5')식의 정렬이 아니라 (4, 5, 4', 5') 식으로 정렬
  6. 가변 키워드 인자 (**kwargs)

나의 경우 3번 문제를 통해 "4.디폴트가 아닌 키워드 온리 인자"는 경험했지만 "5. 디폴트 키워드 온리 인자"는 못했다. 그치만 이해가 되네!!
정말 복잡하지만 순서에 집착하는 변태같은 코딩!

profile
🍎 🍊 🍋 🍏 🍇

0개의 댓글