05 함수

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