Python: 함수와 파라미터

dev-swd·2020년 10월 21일
0

python

목록 보기
11/23
post-thumbnail

함수

프로그래밍을 할 때 반복되는 코드, 특정 용도의 코드를 한 곳에 불러 놓은 것을 뜻한다. 함수를 사용하여, 코드의 용도를 구분하고 재사용하며 실수를 줄일 수 있다.

def 함수이름():
    코드
    
def 함수이름(매개변수1, 매개변수2):
    코드

파이썬에서 함수를 선언할 때는 def (define)키워드를 사용한다.


파이썬은 복수의 리턴 값을 가질 수 있다.

def 함수이름(매개변수):
    return 반환값1, 반환값2

복수로 리턴되는 값은 튜플(tuple) 타잎이다. (반환값1, 반환값2)


함수 선언과 파라미터의 다양한 형태

-고정 파라미터를 갖는 함수

# 단일 파라미터를 갖는 함수
def print_numbers(a):

print_numbers("test") >> # Good
print_numbers() >> # Error


# 복수의 파라미터를 갖는 함수
def print_numbers(a, b):

print_numbers("test1", "test2") >> # Good
print_numbers("test1") >> # Error
print_numbers() >> # Error

단일 또는 복수의 #고정 파라미터를 갖는 함수를 호출 할 때는 반드시 파라미터 갯수 만큼의 값을 지정해야 한다.


-가변 파라미터를 갖는 함수

def print_numbers(*args):

print_numbers("test1", "test2", "test3" ...) # Good
print_numbers() # Good
  1. 함수를 호출할 때 파라미터의 갯수를 무한정(?) 받을 수 있다.
  2. 파라미터로 들어가는 값은 오브젝트이다. (어떠한 데이터 타잎도 가능)
  3. 파라미터를 지정하지 않아도 무방하다. 즉, 생략 가능하다.
  4. 가변 파라미터는 *args 로 명명하는 하자.

-고정, 가변 파라미터를 함께 갖는 함수

def print_numbers(a, b, *c):

print_numbers("test1", "test2", "ok1", "ok2" ...) # Good
print_numbers("test1", "test2") # Good
print_numbers() # Error
  1. 함수 선언 부분에서 가변 파라미터의 위치는 가장 마지막에 와야 한다.
  2. 함수를 호출할 때 고정 파라미터의 갯수에 맞춰서 호출해야 한다.

-키워드 파라미터

def print_member_info(name, phone, email):

print_member_info("swd", "01012341234", "swd@aaa.com")
  1. 파라미터의 위치이에 어떠한 값이 들어가야 할지 명시한다.
  2. 함수 내부의 로직에서 변수의 사용 용도를 명확하게 하여, 유지보수에 좋다.
  3. 파라미터를 명시하고는 있지만, 고정 파라미터이기 때문에 호출할 때 갯수를 맞춰야한다.

-파라미터의 초깃값이 지정된 함수

def print_member_info(name, phone, address="비공개"):

print_memeber_info("swd", "010..", "서울") # Good
print_memeber_info("swd", "010..") # Error
  1. 함수를 호출할 때 초깃값이 지정된 파라미터를 생략할 수 있다.
  2. 함수를 선언할 때 초깃값을 지정한 파라미터는 반드시 마지막에 선언해야한다.

-키워드 파라미터 (keyword only parameter)

def print_member_info(name, phone):

print_member_info(name="swd", "010..") # Error
print_member_info("010..", name="swd")  # Error

함수의 형태는 고정 파라미터와 동일하지만, 함수를 호출 할때 파라미터명을 지정하여 값을 넣어주는 형태를 취한다.
위의 코드에서 2번의 호출은, 2번 모두 에러를 발생시킨다.
첫번째는 문법 오류로 파이썬에 스크립트에 빨간줄이 그어진다.
두번째는 문법 오류는 아니지만, 실행을 해보면 아래와 같은 에러가 발생한다.

호출할 때 넣어주는 2개의 값 모두 name 파라미터를 가리키고 있다는 오류이다.
함수가 호출되는 방식을 생각해보면 왜 에러가 발생하는지 간단하게 알 수 있다.
"010..." 이라는 파라미터는 함수 선언문의 name 이라는 파라미터와 맵핑된다.
name="swd" 이라는 파라미터는 name 이라는 파라미터명을 명시하여 값을 넣어주고 있기 때문에, 이 역시 name 이라는 파라미터명과 맵핑되어, 충돌을 야기한다.
따라서 이 코드가 돌아가게 끔 수정하기 위해서는 아래와 같은 형태가 된다.

def print_member_info(phone, name):

print_member_info("010..", name="swd")  # Good

함수를 선어할 때는 문제가 전혀되지 않았지만, 함수를 어떻게 호출하는지에 따라서
함수를 고쳐야했다.
여기서 "왜 함수 부분을 고쳐야 하지? 호출을 잘못한거 아닌가" 라고 생각이 들었는데, 실제로 호출 부분을 고쳐서 실행을 해보면,

def print_member_info(name, phone):

print_member_info(name="swd", "010..")  # Error


위와 같이 positional .. 에러가 발생한다.
호출할 때 파라미터를 명시적으로 선언한 변수는 잘 들어가지만, 그 뒤에오는
"010.." 이라는 값이 어떤 파라미터에 매핑되어야 하는지 파이썬이 판단하지 못한다.
될 것 같은데.. 안되는 이유를 생각해본다면,,
음.. 함수 호출 부분에서 파라미터 값을 name="swd" 라고 명시적으로 호출하게 되면, 함수 선언 부분의 파라미터에 매핑될 때 순서가 사라지는 느낌이었다. 그래서 "010.." 이라는 값을 어디에 매핑시킬지 모르는 것 같다고 느꼈다.


-딕셔너리 언패킹(dictionary unpacking)

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

x = {'name': '홍길동', 'age': 30, 'address': '서울시 용산구 이촌동'}

personal_info(*x)
personal_info(**x)

*x를 넣으면 x의 키가 출력된다.
**x를 넣으면 키와 값이 언패킹되어, 키와 값이 쌍으로 들어간다.


-키워드 파라미터를 사용하는 가변 인수

def print_member_info(**kwargs):

print_member_info(name="swd", phone="010..") # Good
print_member_info(name="swd", phone="010..", "test") # Error

파라미터 순서에 대한 몇 가지 문제와 함께 정리를 해보자.

1. 함수를 정의 할 때 default value parameter를 non-default value parameter 앞에 정의 하면 안된다고 했는데, 왜 안돼야만 하는가?

기본 값이 선언된 파라미터는 함수의 호출 값을 바꿀 수도 있고, 생략도 가능하다.
이러한 특성에 기반하여 생각해본다면::
함수가 호출되어 값이 파라미터에 매핑될 때, 기본 값이 지정된 파라미터의 값이 바뀌는지, 생략이 되는지 판단할 수 없기 때에 에러가 되어야만 한다.

2. 위치 인수(positional arguments)와 가변 인수(variable length arguments)의 위치가 잘못된 함수를 실행하여 어떤 오류가 뜨는지 확인하고 고쳐보자.

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)


가변 인수가 파라미터의 중간에 위치하여 선언된 함수이다.
이 경우 어떤 값이 age 라는 파라미터에 매핑되어야 할 지 판단할 수 없기 때문에 에러가 발생한다.
수정해보면,,

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

# 결과 값
name=정우성
args=('01012341234', 'seoul')
age=20

이 때 센스있게 호출 부분에서 20을 age 의 위치로 바꿔주자.

3. 가변 키워드 인수 (variable length keyword arguments)의 위치가 잘못된 함수를 실행하여 어떤 오류가 뜨는지 확인하고 고쳐보자.

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


가변 키워드 인수가 중간에 위치하고, 초깃값이 지정된 파라미터가 가장 마지막에 위치한 형태의 함수이다. 같은 맥락으로 가변 인수가 중간에 위치할 경우, 그 위의 파라미터를 어떠한 값에 매핑해야 할지 판단할 수 없기 때문에 에러가 발생한다.
수정해보면,,

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

# 실행 결과
name=정우성
age=20
kwargs={'mobile': '01012341234'}
address=seoul

역시 센스있게 호출 부분의 address="seoul" 의 위치를 함수의 파라미터 위치에 알맞게 바꿔주자.

4. 위치 인수와 키워드 가변 키워드 인수 (variable length keyword arguments)의 위치가 잘못 선언된 함수를 실행하여 어떤 오류가 뜨는지 보고, 수정해보자.

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. 일단 가변 인수키워드 가변인수 가 동시에 쓰였다. 뒤로 보내주자.
2. 초깃값이 선언된 파라미터는 고정 파라미터 뒤로 보내주자.
3. 고치다보니 함수의 호출 부분도 문제가 있어보이니 같이 바꿔주자.

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

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

이렇게 해놓고 보니, 아래와 같이 호출 부분에서 에러가 발생하고 있다.

다시 천천히 생각해보면, 아까 키워드 파라미터 부분에서 봤던 에러와 비슷하다.
호출 부분에서 파라미터를 명시적으로 지정했을 때, 함수 선언부를 수정했어야 했던..
순서가 사라지는 느낌.
그래서 함수 선언 부분과 호출 부분 둘 다 수정해보았다.

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

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

조금 복잡해진 형태인데,,

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

이 부분에서 호출 할 때 생략 가능한 부분은 어디일까?

name >> 생략 가능하다. 기본 값이 있으니까.
*agrs >> 생략 가능하다. 가변이니까.
**kargs >> 생략 가능하다. 가변이니까.

그럼 생략 가능하지 않은 부분은 어디일까?

age: 고정
address: 고정

그런데 호출할 때 address="값" 의 형태는 **kargs 의 형태이다.
따라서, 순서는 아래와 같이 되었다.

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

뭔가 이론적으로 정리를 하고 싶지만, 좀 어려운 내용이라 나중에 다시 짚어보기로 하였다.
참고로 조사한 바로는 가변 인자 *args 와 **kargs 는 함수 선언부에 마지막에 와야 하는 것이 #절대가 아니었다.

참조 link:

profile
개발을 취미로 할 수 있는 그 때 까지

1개의 댓글

comment-user-thumbnail
2022년 1월 14일

정리 잘해놓으셨네요 잘보구 갑니다

답글 달기