05 함수
2020년02월14일05 함수
참고
애스크장고 AskDjango
함수
- 함수는 코드 중복을 제거하기 위해 사용된다.
- 구성
- 1개의 함수명 (필수)
- 0개 이상의 인자값 (선택)
- 1개의 반환값 (선택) 반환값이 없는 경우에는 None을 리턴한다.
함수 유형
- 인자 값, 반환 값 없는 함수
def myfn1(): result = 1 + 2 print(myfn1()) # 호출했지만, 반환값이 없어서 None 출력
- 인자 값은 있지만, 반환 값은 없는 함수
def myfn2(a, b, c): result = a + b + c print(myfn2(1, 2, 3)) # 호출해도 반환값이 없어서 None 출력
- 인자 값은 없지만, 반환 값은 있는 함수
def myfn3(): return 10 print(myfn3()) # 10 출력
- 인자 값과 반환 값이 모두 있는 함수
def myfn4(a, b, c): result = a + b + c return result print(myfn4(1, 2, 3)) # 6 출력
Scope(변수의 유효 범위)
- 변수가 선언되어, 해당 변수가 영향을 미치는 영역
- 지역 변수(Local Variable): 함수 안에서 선언되어, 함수 내에서만 활용이 가능한 변수.
- 전역 변수(Global Variable): 함수 밖에서 선언되어, 함수 안에서도 활용이 가능한 변수.
전역 변수같은 경우에는 코드의 가독성을 헤치므로 권장하지 않는다. 지역변수를 사용하여 값이 변동되어도, 버그 발생 확률을 낮출 수 있다. 하지만, 상수문법이 없는 파이썬에서 변수명을 전부 대문자로 입력하여 관례적으로 상수처럼 사용하기도 한다.
Positional/Keyword Arguments
인자
함수가 실행되는데 필요한 0개 이상의 변수 목록
Positional Arguments
인자의 위치에 기반한 인자
def fn_with_positional_arguments(name,age):
print('이름: {} 나이: {}'.format(name,age))
fn_with_positional_arguments('Tom',10)
Keyword Arguments
- 인자의 이름에 기반한 인자
- 디폴트 인자 문법이 함께 적용
- 함수 호출 시에 해당 인자를 지정하지 않으면, 디폴트 인자값으로 값이 자동지정
- key를 입력하지 않으면 위치기반으로 적용된다.
def fn_with_keyword_arguments(name="", age=0):
print('이름: {} 나이: {}'.format(name,age))
# 키워드로 하면 순서 상관없다.
fn_with_keyword_arguments(name='Tom', age=10)
fn_with_keyword_arguments(age=10, name='Tom')
# 인자 지정하지 않으면, 디폴트 값으로 적용
fn_with_keyword_arguments(age=10)
fn_with_keyword_arguments(name='Tom')
# 키를 입력하지 않으면 위치 기반으로 적용
fn_with_keyword_arguments('Tom', 10)
기본 인자값은 함수가 실행될 때 계산되지 않고, 함수를 ‘정의’할 때 계산된다. 이러한 특성때문에 리스트나, 딕셔너리같은 mutuable한 데이터 타입은 문제를 일으킬 수 있다.
def buggy(arg, result=[]):
result.append(arg)
print(result)
처음 함수를 실행시에는 문제가 없어 보인다.
buggy(‘a’) [‘a’]
두번째로 함수를 실행했는데, ‘b’만 출력되는 것이 아니라 그 전의 ‘a’의 값도 남아 있는 것이다.
buggy(‘b’) [‘a’,’b’]
위에서 말했듯이, 기본 인자값은 정의 시 계산되기 때문에, result=[]는 메모리 어딘가에 지정이 되어있다. 그리고 리스트나 딕셔너리같은 mutuable 데이터 타입은 해당 메모리의 값을 변경할 수 있기 때문에 값을 변경해도 같은 메모리 주소에 반영이 된다. 그렇기에 위처럼 계속 기록이 되는 것이다.
위의 상황을 해결하긴 위해서 다음과 같이 작성해야 한다.
def nonbuggy(arg, result=None): #result를 None으로 지정
if result is None:
result = []
result.append(arg)
print(result)
Packing
인자의 개수를 제한하지 않고, 다수의 인자를 받을 수 있음 다수의 Positional Arguments를 하나의 tuple로 받는다.
def fn2(*colors):
for color in colors:
print(color)
fn2()
fn2('white')
fn2('white','yellow')
fn2('white','yellow','black','pink')
def fn3(color1, color2, *other_colors):
print('color1:', color1)
print('color2:', color2)
for color in other_colors:
print(color)
# 최소 2개의 인자 지정이 필요하다. 부족하면 TypeError
fn3('brown') # TypeError 발생
fn3('brown','green')
fn3('brown','green','white')
fn3('brown','green','whilte','yellow')
Unpacking
인자를 넘길 때 Sequence Data Type(리스트/튜플 등)을 다수의 인자인 것처럼 나눠서 전달 가능
colors = ['white', 'yellow', 'black']
fn2(*colors) #white, yellow, black으로 3개 전달
fn2('brown','pink',*colors)
#brown, pink, white, yellow, black으로 5개 전달
other_colors = ('violet', 'coral', 'cyan')
fn2('brown', 'pink', *colors, *other_colors)
#brown, pink, white, yellow, black, violet, coral, cyan
fn3('purple', *('aqua', 'beige', 'black'))
#purple, aqua, beige, black 튜플도 언패킹 가능
익명함수 (Anonymous Function)
lambda를 사용하여 익명 함수를 사용할 수 있다.
- return문을 쓰지 않아도, 마지막 값을 리턴값으로 처리
- 대개 인자로 1줄 함수를 지정할 때 많이 쓰임.
- 일반 함수와 인자처리도 동일하게 처리된다.
# 인자 두 개를 받고 x + y 값은 반환하는 의미이다.
(lambda x, y: x + y)(1,2) # 바로 실행할 때
mysum3 = lambda *args: sum(args) # mysum에 할당
print(mysum3(1,2,3,4,5,6,7) # 28
1급객체
다른 객체들에 적용 가능한 연산을 모두 지원하는 객체
- 인자로 넘기기, 변수에 대입하기 등
- 종류: 일급 함수/클래스/컨트롤/타입/데이터타입 등
파이썬은 1급 함수/클래스를 지원한다.
- 함수/클래스를 런타임에 생성 가능.
- 함수/클래스를 변수에 할당이 가능
- 함수/클래스를 인자나 리턴값으로서 전달 가능.
익명함수를 mysum1에 할당하고 이를 또 mysum2에 할당해도 잘 실행 된다.
mysum1 = lambda x, y: x + y
mysum2 = mysum1
mysum2(10,20) -> 30
함수를 인자로 받아 호출할 수 있다.
def myfn(fn, x, y):
return fn(x,y)
myfn(mysum1, 10, 20) -> 30
myfn(lambda x,y:x*y, 10,20) -> 200
# 익명함수를 인자로 가능하다.
# 추후에 데코레이터에서 유용하게 사용할 수 있다.
고차함수 (Hign Order Function)
다른 함수를 생산/소비하는 함수 다른 함수를 인자로 받거나, 그 결과로 함수를 반환하는 함수
def base_calculator(base):
wrap = lambda x, y: base + x + y
return wrap
calc_10 = base_calculator(10)
# 이렇게 하면, calc_10은 lambda x, y: 10 + x +y의 함수를 가지게 된다.
calc_10(1,2) # 13
calc_10(10,20) # 40