나의 경험담

공부법

저도 대부분의 경우와 마찬가지로 Python 강의를 보면서 공부를 시작했습니다
그러다보니 알려주는 대로 (특정 예시와 사용법) 받아들이기만 하다보니 개별적 사용법을 외워야 하는건가? 하는 답답함과 사고의 틀이 닫히더라구요

저에게는 프로그래밍 언어 사용법을 알려주는 강의는 의미가 없는 공부법이였습니다. 개별적 사용법을 외우기도 좀 그렇고, 실제 필요한 code가 아닌 강의를 위한 code를 따라 치다보기만 하다보니, 계속 까먹게 되더군요

(물리학을 좋아했던 이유도 동작 원리를 파악하고 일반화 한 식을 토대로 여러 상황에 적용할 수 있어서 좋아했었습니다)

그리고 진짜 화났던 점은, 강의만 듣던 저는 args 또한 예약어(?)처럼 기능이 정해져있던줄 알았습니다 ㅋㅋ

그러나 우연찮게 구글링 중 args는 단순히 naming convention 임을 알게됐고
그 순간부터 강의가 아닌 help(), dir(), 구글링과 Docs를 가까히 하면서 진짜 공부를 시작하게됬습니다


내게 공부법을 알려준 선생님 *args

print 함수를 분석했을때
다음과 같은 정의를 볼 수 있었습니다

def print(...중략..., *args, ...중략...):

정의부분의 print 인자로 보이는 *args 가 뭔지 궁금했습니다 (사실 이때는 인자라는 말도 몰랐습니다)
처음 접하는지라 어디서 들어본 'parameter', '*', 'args' 를 조합해서 검색해 봤습니다

  1. args는 argument의 약자라는 것
  2. parameter는 함수 호출시 넣는 변수
  3. *(asterisk)를 붙이면 여러개를 받을 수 있다는 것

을 알게됬습니다

또한 중간 중간 모르는 개념들이 참 많이 쏟아졌었습니다
꼬리에 꼬리를 물어 지금까지 왔네요 ㅎㅎ


"꼬꼬공"

언어 공부 시작하고 약 2주일 차부터 이와 같은 공부법으로
궁금증 해소를 위한 공부(이전 포스팅에서 언급한 꼬리에 꼬리를 무는 공부 "꼬꼬공"^^)를 하니
Python이 점점 친숙해 지는게 느껴집니다!!

(그래도 이러한 공부법으로 전환한 시점이 늦지 않았던 것 같아 다행이라 생각합니다)

저의 노션 페이지 일부입니다
구글링 중 모르는 개념을 검색해보고 저만의 언어로 기록해둔 부분입니다

다시 돌아보니 진짜 모르는것도 많았네요 ㅋㅋ
조각 조각의 지식이 연결성 없을 수 있고
특정 관점에서는 공부 효율이 떨어져 보일수도 있겠습니다만

3개월가량이 흐른 지금, 조각조각의 지식이 연결되니 제게는 튼튼한 Python 기초지식이 되었습니다!

아는 것이 점점 쌓여간다면 개발환경에서 그때그때 찾아서 할 수 있습니다

오히려 저에게 이런 공부법은 많은 검색을 통해
Python 및 CS 지식, 웹 개발 등의 큰 틀을 볼 수 있게 되었기에 효율적이었다고 할 수 도 있겠습니다!

놀라운 점은 Python에서 아는 것이 점점 쌓여가면서 점점 개발환경에서 그때그때 찾아서 할 수 있게 되었습니다.

이런 개인적인 이야기를 하는 이유는 *args를 본 후로 이러한 공부법으로 공부하기 시작했기 때문입니다
사실상 *args가 제게 공부법을 알려준 선생님인 셈이네요 ㅋㅋ


스스로 공부하기 위한 도구 help(), dir(), 공식문서 링크



이제 진짜 주제를 시작해 보겠습니다

>>> print("hello world")
hello world
>>> print(3)
3

"함수 호출시 소괄호 안에 값을 그냥 아무 값이나 넣으면 알아서 해결되는 줄 알았는데..."

인자를 넣어주는 규칙이 존재합니다

그렇다면 우선 인자가 어떤 개념인지 알아야겠죠?


argument, parameter

인자(argument)는 함수 호출 시 괄호 안의 값들을 의미하고

매개변수(parameter)는 함수 정의 시 괄호 안의 값들을 의미합니다

즉, 함수 호출 시 인자로 값을 넣으면 함수 정의로 넘어가서 매개변수로써 수행합니다

  • 자주 접했던 수학의 함수 개념과 동일합니다
    • y = x + 3 이라는 함수가 존재합니다.
    • 저는 이 함수의 x에 5를 넣고싶습니다

"x라는 매개변수에, 5라는 인자를 넣는다"고 표현할수 있겠습니다

거의 혼용해서 써도 무관하지만 개념적으로는 알아두시면 좋겠습니다


keyword 인자 (keyword argument)

# parameter
def today(year, month, day):
	print(f"오늘은 {year}년 {month}월 {day}일 입니다.")

# keyword argument
>>> today(day=3, year=2022, month=4)
오늘은 2022년 4월 3일 입니다.

매개변수는 year, month, day 순 이지만
인자는 day=30, year=2022, month=4 로 넘겨주었습니다

순서 상관없이
인자의 변수명과 매개변수의 변수명을 매칭해서 값을 넘겨줍니다

keyword 인자 라고 불리는 이유를 아시겠나요?

위치 인자(positional argument)

위치 인자는 평소에 자주 보던 형식의 인자값 일 것입니다

# parameter
def sum(num1, num2):
	return num1 + num2

# positional argument
sum(1, 2)

함수 내부에서 parameter 값으로 다음 값이 할당됩니다

num1 = 1
num2 = 2

# parameter
def sum(num1, num2):
	return num1 + num2

# positional argument
sum(2, 1)

함수 내부에서 parameter 값으로 다음 값이 할당됩니다

num1 = 2
num2 = 1

즉, 인자의 위치를 통해 parameter에 전달됩니다

위치 인자 라고 불리는 이유를 아시겠나요?

keyword, positional

간단한 처리에는 위치 인자가 간편할 수도 있겠지만
인자값 구성이 복잡해진다면 keyword 인자로 작성하는 것이 잘 읽히겠죠?

만약 같이 쓴다면 어떨까요?

# parameter
def today(year, month, day):
	print(f"오늘은 {year}{month}{day}일 입니다.")

# keyword , positional
today(month=4, 3, year = 2022)

어떤 결과가 예상되시나요?

month, year 인자는 매개변수에 찾아서 넣어주고

남은 인자 3은, 당연히 남은 매개변수인 day로 찾아서 들어갈까요?

"그렇게 생각하신다면 아직 인간적 감성이 남으신 분 이시군요 ㅋㅋ"

  File "main.py", line 6
    today(month=4, 3, year = 2022)
                   ^
SyntaxError: positional argument follows keyword argument

위의 코드를 실행시키면

SyntaxError가 발생합니다
안내 메시지처럼 위치인수, keyword 인수 순으로 써주어야 합니다

그럼 해결 됬겟쬬?

# parameter
def today(year, month, day):
	print(f"오늘은 {year}{month}{day}일 입니다.")

# keyword , positional 
today(3, month=4, year = 2022)

"땡!" (나영석 톤)

Traceback (most recent call last):
  File "main.py", line 6, in <module>
    today(3, month=4, year = 2022)
TypeError: today() got multiple values for argument 'year'

year로 여러개의 인자값이 들어왔다고 하네요

감이 오시나요?

인자 3은 위치인자로써 매개변수 year에 할당되었지만
인자 year = 2022는 keyword 인자로써 매개변수 year에 또 할당하려 하네요


인자 naming convention

args

인자(argument)를 줄여서 args로 씁니다
(args는 단순히 naming convention 입니다. 아무거나 써도 상관 없습니다)

kwargs

마찬가지로 keyword argument를 줄여서 kwargs로 씁니다
(kwargs또한 naming convention입니다. 아무거나 써도 상관 없습니다)

함수 호출 시 넣어주는 인자는 parameter 값으로 넣어줄 인자 이기에
함수 정의 시 parameter로 args, kwargs라고 쓰는 것 입니다

"납득이 가는 논리입니다. 그렇죠?" (끄덕끄덕)


번외 kwds

help(type)
**kwds라고 쓰여있길래 이 자체가 특별한 무엇인가 라고 생각했었을때가 있었습니다 ㅋㅋ
-> kwds는 naming convention을 지키지 않고 쓴 변수명이고 **가 의미 있는 부분입니다!


naming convention 관련 PEP 블로그 링크


variable length / Asterisk (*)

함수 호출 시 넣어주는 인자는 parameter 값으로 넣어줄 인자 이기에
함수 정의 시 parameter로 args, kwargs라고 쓰는 것 입니다

라고 했었는데요
정확하게는 가변 일때 써주는 naming convention 입니다

예시를 통해 가변 길이 (variable length) 에 대해 알아보겠습니다

가변 인자(variable length arguments)

위에서 썻던 sum 함수 입니다

# parameter
def sum(num1, num2):
	return num1 + num2

# positional argument
sum(1, 2)

만약 숫자를 하나 더 추가하고 싶다면 어떻게 하시겠습니까?

# parameter
def sum(num1, num2, num3):
	return num1 + num2 + num3

# positional argument
sum(1, 2, 3)

함수에 넘겨주는 인자의 갯수만큼 매개변수의 갯수도 추가해주어야 합니다

그러나 매번 함수를 수정할 수는 없습니다

그래서 쓰는 개념이 가변 인자(variable length arguments) 입니다

# parameter
def hello world(*args):
	return 

# positional argument
hello world(1, 2, 3)

위치 인자를 여러개 썻지만 매개변수로는 *args을 통해 한꺼번에 넘겨줄 수 있습니다
이러한 개념이 가변 인자 입니다

args 대신 aaa 등 아무 변수명이나 가능합니다
asterisk(*)를 통해 가변 인자임을 나타내는 것 입니다

예제(가변 인자)

예제를 풀어보겠습니다

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)

"정우성"은 name 으로 넘겨주고 , 20 은 age 으로 넘겨주고

남은 "01012341234", "seoul"는 여러개 위치 인자를 받는 *args로 넘겨줄것 같으신가요?

"그렇게 생각하신다면 아직 인간적 감성이 남으신 분 이시군요 ㅋㅋ"

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

왜 이런 오류가 발생했을까요?
*args 가 20까지 넘겨받기 때문입니다.
즉, 함수는 age를 받지 못한겁니다

해결하려면
인자: age = 20으로 keyword 인자로 써주거나
매개변수: 위치인자, 가변 인자 순으로 써주어야 합니다

가변 keyword 인자 (variable keyword length arguments)

가변 keyword 인자 또한 가변 인자와 같은 개념으로써, 여러개의 keyword 인자를 받기 위한 개념입니다
가변 keyword 인자는 double asterisk(**)를 통해 나타냅니다

예제(가변 keyword 인자)

예제를 풀어보겠습니다

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")

"정우성"은 name 으로 넘겨주고, "20"은 age 으로 넘겨주고 address="seoul" 으로 넘겨주고

남은 mobile="01012341234"를 **kwargs로 넘겨줄 것 같으신가요?

"그렇게 생각하신다면 아직 인간적 감성이 남으신 분 이시군요 ㅋㅋ"

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

왜 이런 오류가 발생했을까요?
**kwargs가 address="seoul"까지 넘겨받기 때문입니다.

그러나 address="seoul" 넘겨받고 address=0로 덮어써지면 말되지 않냐! 라고 할 수도 있겠습니다만

컴퓨터는 인간처럼 행동하지 않습니다 ^^

애당초 keyword 로 매칭 해서 값을 찾는 형태이기 때문에
여러값을 받아들이는 가변 keyword 인자 이후 순서로 keyword 인자를 둘수 없는 것 입니다

"납득이 가는 논리입니다. 그렇죠?" (끄덕끄덕)

예제(가변 인자, 가변 keyword 인자)

예제를 풀어보겠습니다

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")

"이제는 감이 오시죠?" (끄덕끄덕)

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

해결해 보겠습니다

1. address 매개변수를 가변 keyword 인자 앞으로 옮기겠습니다

# address 매개변수를 가변 keyword 인자 앞으로 
def mixed_params(name="아이유", *args, age, 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")
Traceback (most recent call last):
  File "main.py", line 8, in <module>
    mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")
TypeError: mixed_params() missing 1 required keyword-only argument: 'age'

2. 기본값 없는(non-default value) 매개변수를 기본값 있는(default-value) 매개변수 앞으로 옮기겠습니다

# 기본값 없는(non-default value) 매개변수를 기본값 있는(default-value) 매개변수 앞으로
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

근데 의문점 안생기시나요?
기본값 없는 매개변수를 기본값 있는 매개변수 앞으로 옮기겠다고 했는데, 매개변수 address 는 옮기지 않았습니다!

하지만 의문점은 금세 해결되시죠?
keyword 인자로써 매칭이 가능하기 때문입니다 (가변 keyword 인자로 넘어가기 전, address에 매칭 가능함!)


매개변수 순서

예제를 통해 경험했듯
매개변수는 순서가 존재합니다

매개변수의 순서 다음과 같습니다

  1. 위치 인자 (positional arguments)
  2. 기본값 인자 (default value arguments)
  3. 가변 인자 (varialbe positional arguments)
  4. keyword 인자 (keyword arguments)
  5. keyword 기본값 인자 (keyword default value arguments)
  6. 가변 keyword 인자 (varialbe keyword arguments)
profile
궁금증 주도 공부 / 원리 파고들기 / 경험에 기반한 블로그

0개의 댓글