Python 정리 - 함수(function)

Kyung Jae, Cheong·2023년 3월 23일
0
post-thumbnail

함수 (function)

  • 이번 글에서는 파이썬에서 많이 쓰이는 함수의 정의부터 다양한 활용법에 대해 다루고자 함

1. 함수의 정의, 함수의 호출

  • 프로그래밍을 진행하다보면 동일한 코드를 몇 번이고 동일하게 처리해줘야하는 경우가 있음
  • 함수란 인수(변수)를 입력 받아 코드를 실행하고 결과물을 출력하도록 하는 입력값과 출력값의 관계를 의미함
    • 쉽게 말해 입력값을 받고 출력값을 계산하는 기계 혹은 틀
  • 파이썬에서는 def라는 구문을 통해서 함수를 정의할 수 있으며, 함수를 작성하는 행위를 함수를 정의한다라고 표현함
    • 이렇게 정의된 함수는 함수명을 통해 기능을 수행하도록 불러올 수 있고, 이러한 행위는 함수를 호출한다라고 표현함
# 함수의 정의
def 함수명(인수 목록):
  실행구문
  ...
  return 반환값

# 함수의 호출
함수명(인수 목록)
  • 간단한 함수의 예시
# 반환값 없이 출력만 실행
def hello(var):			# 정의
  print('Hello', var)

hello('python')			# 호출
'''
Hello python
'''

# 함수의 반환값을 변수로써 저장
def sum_num(num1, num2):	# 정의
    print(f"num1 : {num1}, num2 : {num2}")
    return num1 + num2		# 반환

sum_num_12 = sum_num(3,6)	# 호출
print(f"sum : {sum_num_12}")

'''
num1 : 3, num2 : 6
sum : 9
'''
  • 함수의 정의를 함수의 호출보다 먼저 시행해야하는 것이 원칙이긴하지만, 실제로는 동일한 코드 파일 안에서는 호출을 먼저하고 정의를 뒤에 해주어도 동작 오류가 발생하지는 않긴함
    • 이는 객체지향프로그래밍(OOP)의 특징을 가지기 때문이라 설명할 수 있는데, 이에 대한 내용은 뒤에 다시 설명할 예정)
  • 함수를 한번 정의하면 해당 함수는 몇번이고 호출하여 재사용할 수 있기 때문에 반복적으로 작업을 수행하는 경우 훨씬 효율적인 프로그래밍이 가능해짐

2. 함수의 인수(argument)

  • 함수에게 전달하는 정보를 인수(argument)라하며, 이는 매개변수(parameter)라고도 불림
  • 함수를 정의할때, 함수명 뒤에 소괄호()에 인수를 담아서 함수에 전달하게 됨
    • 소괄호에 묶어서 전달한다는 것은 튜플의 형태로 값을 전달한다는 것과 같은 의미이기 때문에, 함수를 정의할 때의 인수의 순서와 함수를 호출할 때의 인수의 순서가 일치해야함을 의미함
    • 순서가 중요한 것은 인수의 변수명을 지정하지 않고 값만을 넣어서 호출하는 경우에 해당하는 것이고, 호출시 변수명을 직접 적어주는 경우엔 순서를 맞춰서 넣어줄 필요는 없음
    • 다만 일부의 변수만을 따로 지정하는 경우엔, 앞 쪽 변수는 순서를 반드시 맞춰줘야하고, 나머지 변수들은 기본값이 지정되지 않은 경우 반드시 값을 정의해 주어야 함
  • 모든 함수가 인수를 반드시 가져야 할 필요는 없어서, 인수를 따로 정의하지 않고도 함수를 정의하고 호출할 수 있음
    • 이때는 호출할 때 어떠한 인수도 넣지 않아야 오류가 발생하지 않음
# 인수(매개변수)를 지정하여 함수를 정의하기
def sums(num1, num2, num3):
    sum_num = num1 + num2 + num3
    return sum_num

# 순서를 반드시 맞추어서 호출
sum_1 = sums(3, 6, 9)
print(sum_1)
'''
18
'''

# 앞쪽은 순서를 맞추어주고, 나머지는 순서 관계 없이 직접 지정
sum_2 = sums(3, num3=9, num2=6)
print(sum_2) 
'''
18
'''
# 인수의 기본값을 미리 지정하여 정의하는 경우
def sums(num1, num2, num3=10):
    sum_num = num1 + num2 + num3
    return sum_num

# 기본값이 지정되지 않은 변수는 반드시 지정해야함
sum_1 = sums(1, 2)	# num3=10
print(sum_1)
'''
13
'''

# 기본값이 지정되어도 변수값을 새로 지정할 수 있음
sum_2 = sums(1, 2, 5)
print(sum_2)
'''
8
'''

sum_3 = sums(1, num2=3)
print(sum_3)
'''
14
'''
  • Python에서는 함수를 정의할 때 인수 앞에 *를 붙임으로써 콤마,로 구분한 인수를 한번에 여러개 전달할 수 있으며, 이때 전달된 변수는 함수 내부에서 튜플로 저장됨
    • 이러한 경우 일반적으로는 *args라는 이름으로 설정함
def func(*args):
  print(args)

func(1,2,3,4,5)
'''
(1, 2, 3, 4, 5)
'''
  • 함수를 정의할 때 인수 앞에 **를 붙이면 키워드로 구분된 인수들을 한번에 여러개 전달할 수 있으며, 이때 전달된 변수는 함수 내부에서 딕셔너리 형태로 저장됨
    • 이러한 경우 일반적으로는 **kwargs아는 이름으로 설정함
def func(**kwargs):
  print(kwargs)

func( a=1, b=2, c=3, d=4)
'''
{'a':1, 'b':2, 'c':3, 'd':4}
'''
  • *args**kwargs처럼 인수의 개수를 정하지 않고 정의하는 경우, 이러한 인수를 가변길이인수(variadic argument)라 부름

3. 전역변수와 지역변수

  • 파이썬에서 변수는 크게 전역변수(global), 지역변수(local) 두 종류로 구분할 수 있고, 전역변수와 지역변수는 정의되는 위치와 적용되는 범위에 있어 차이가 있음
  • 지역변수 (local variables) : 함수 내부에서 정의되어 함수 내부에서만 쓰일 수 있는 변수
    • 함수가 종료되면 메모리에 더이상 저장되지 않고 제거됨
  • 전역변수 (global variables) : 하나의 파이썬 파일에 있는 모든 함수나 코드에 쓰일 수 있는 변수
    • 함수 외부에서 정의된 변수는 global 변수로써 함수 내부에서도 쓰일 수 있음
    • 함수 내부에서 global 구문으로 정의된 변수는 함수 안에서 정의되었지만 전역변수로 저장되어 동일한 파이썬 파일내에 모든 함수나 코드에서 쓰일 수 있음
  • 이때 각 변수명이 이용될 수 있는 통용 범위를 스코프(scope)라고 부름
# 전역변수
g_var = '전역변수'

# 함수 정의
def variables():
    
    # 지역변수
    local_var = '지역변수'
    
    # 전역변수 2
    global global_var
    global_var = '함수 내부 전역변수'
    
    print('--함수 내부 변수들--')
    print('외부 전역변수 g_var : ', g_var)
    print('내부 전역변수 global_var : ', global_var)
    print('함수 지역변수 local_var : ', local_var)

# 외부에서 변수 접근하기
variables()

print('\n--함수 외부 변수들--')
print('외부 전역변수 g_var : ', g_var)
print('내부 전역변수 global_var : ', global_var)
print('함수 지역변수 local_var : ', local_var)

'''
--함수 내부 변수들--
외부 전역변수 g_var :  함수 외부 전역변수
내부 전역변수 global_var :  함수 내부 전역변수
함수 지역변수 local_var :  지역변수

--함수 외부 변수들--
외부 전역변수 g_var :  함수 외부 전역변수
내부 전역변수 global_var :  함수 내부 전역변수
NameError: name 'local_var' is not defined
'''
# 지역변수는 함수 외부에서 접근하면 오류가 발생함!
  • 이처럼 지역변수는 함수 내부에서만 저장되고 이용되며, 함수 내부에서는 global 구문을 통해서 함수 내부에서 정의된 변수를 전역변수로써 저장하여 이용할 수 있음
  • 이러한 전역변수와 지역변수가 정의되는 위치와 적용되는 범위를 고려하여 코드를 작성하는 것이 중요함

4. lambda 연산자

  • 간단한 함수를 정의하는 경우에는 lambda 연산자(lambda operator)를 통해 보다 효율적이고 간결한 코드를 작성할수 있음.
  • lambda 함수명을 지정하지 않고도 함수를 정의하고 적용할 수 있음
    • 이러한 특성 때문에 람다함수는 무명함수 혹은 익명함수라고도 불림 (anonymous fuction)
# 람다 연산자의 기본 구조
lambda 인수:
# 람다 함수 사용 예시
multi_words = lambda word1, num : word1 * num

# 함수호출
result = multi_words('word!\t', 5)

print(result)
'''
word!	word!	word!	word!	word!	
'''
  • map()함수를 활용하여 이터레이터(iterator) 요소별로 함수를 적용할 수 있음
    • map(함수, 이터레이터)
    • map 함수는 이터레이터(iterator)를 반환함 (for문에 쓰이기 적합!)
# 각 요소를 2배씩 곱해보자
data = [1,2,3,4,5]

# for문으로만 적용한 경우 1
for d in data:
    print(d*2)
'''
2
4
6
8
10
'''

# for문으로만 적용한 경우 2
for d in [x*2 for x in data]: # 리스트 컴프리헨션
    print(d)
'''
2
4
6
8
10
'''

# map & lambda 적용
for d in map(lambda x: x*2, data):
    print(d)
'''
2
4
6
8
10
'''
# 각 문자열에 "!!!"를 각각 붙여보자
str_list = ['test1', 'test2', 'test4test5', 'test3']

# 람다 함수 적용 (이터레이터)
shout_str = map(lambda item : item + '!!!', str_list)

# iterator -> list
shout_list = list(shout_str)

print(shout_list)
'''
['test1!!!', 'test2!!!', 'test4test5!!!', 'test3!!!']
'''
  • filter() 함수를 활용하여 이터레이터 요소를 조건에 맞게 걸러낼 수 있음
    • filter(함수, 이터레이터)
    • filter 함수는 이터레이터(iterator)를 반환함 (for문에 쓰이기 적합!)
# 리스트 요소 중 2의 배수만을 걸러내보자
data = [1,2,3,4,5,6,7,8,9]

# for문과 if문으로 구현
for d in data:
    if d % 2 == 1:
        continue
    else:
        print(d)
'''
2
4
6
8
'''

# for문과 if문으로 구현 (컴프리헨션)
for d in [x for x in data if x % 2 == 0]:
    print(d)
'''
2
4
6
8
'''

# filter & lambda 적용
for d in filter(lambda x : x % 2 == 0, data):
    print(d)
'''
2
4
6
8
'''
# 문자열 길이가 6 이상인 데이터만 걸러내보자
users = ['frodo', 'samwise', 'merry', 'pippin', 'aragorn', 'boromir', 'legolas', 'gimli', 'gandalf']

# lambda적용 (이터레이터를 반환)
result = filter(lambda u : len(u) >= 6, users)

# iterator -> list
result_list = list(result)

print(result_list)
'''
['samwise', 'pippin', 'aragorn', 'boromir', 'legolas', 'gandalf']
'''

5. 데코레이터

  • 이번에는 복잡한 함수의 경우에 적용되는 데코레이터를 다루어봄
  • 함수를 인자로 받아서 기능을 추가한 뒤에 다시 함수를 반환하는 경우엔 코드가 다소 복잡해질 수 있고, 매번 설정하기에 복잡한 경우가 있음
    • 이러한 문제를 데코레이터 함수를 통해 해결할 수 있음
  • 데코레이터 함수를 정의하고, 데코레이터 함수를 적용할 함수의 윗줄에 @를 붙여줌으로써 데코레이터 기능을 사용할 수 있음
# 데코레이터 함수 정의
def deco( func ): # 함수를 인자로 받음
  def wrapper( var ) : # 추가할기능들을 묶는 함수를 정의
    추가 기능
    return 반환변수
  return wrapper	# 안쪽에 묶은 함수를 반환함

# 데코레이터 함수 적용
@deco	# 데코레이터 함수명
def 기능을 추가하려는 함수:
  ...
  • 데코레이터 사용 예시 (문자열을 변환하여 출력하기)
def deco(func):
    def wrapper(x):
        xx = '---' + x + '---'
        return func(xx)
    return wrapper

@deco
def print_msg(msg):
    print(f"{msg}를 입력했습니다.")

message = "Hello!"

print_msg(message)
'''
---Hello!---를 입력했습니다.
'''
  • 데코레이터 사용 예시 (함수 실행 소요시간 측정하기)
import time
from functools import wraps

# 데코레이터 함수 정의
def check_time(func):
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        
        start_time = time.time()
        
        result = func(*args, **kwargs)
        
        end_time = time.time()
        
        print("@check_time of '{0:s}' took {1:e} seconds"
              .format(func.__name__, end_time - start_time))
        
        return result
    
    return wrapper

# 데코레이터 함수 적용 1
@check_time
def sum_num_for(n):
    s = 0
    for i in range(1, n+1):
        s += i
    return s

sum_num_for(100000)
'''
@check_time of 'sum_num_for' took 4.498243e-03 seconds
5000050000
'''

# 데코레이터 함수 적용 2
@check_time
def sum_num(n):
    return n * (n + 1) / 2

sum_num(100000)
'''
@check_time of 'sum_num' took 0.000000e+00 seconds
5000050000.0
'''

6. 제너레이터

  • 파이썬에서는 반복문을 통해 얻은 요소를 이터레이터(iterator)로 반환하는 함수를 정의할 수 있는데, 이러한 함수를 제너레이터(generator)라고함
  • 함수 내부에서 yield문을 통해 각 요소를 반환하도록 정의할수 있고, 이 때는 return문을 사용하지 않아야 함
  • 무한 루프에 빠지는 경우에도 이터레이터(iterator)를 생성할 수 있지만, 이를 for문으로 이용하면 무한루프에 빠지게 되므로.. 이부분은 조심해서 사용할 필요가 있음
  • 이터레이터(iterator)에 next(이터레이터)함수를 이용하면, 요소를 하나씩 살펴 볼 수 있음
# 제너레이터
def make_iter(x):
    while True:
        yield x
        x += 1

iterator = make_iter(0)
print(iterator)
'''
<generator object make_iter at 0x000002A9ACB39DC8>
'''

# next()
print(next(iterator))
print(next(iterator))
print(next(iterator))
'''
0
1
2
'''
# 제너레이터 예시 (for문에서 사용해보기)
def make_iter(min_x, max_x):
    x = min_x
    while True:
        yield x
        
        if x < max_x:
            x += 1
        else:
            break
        
# 이터레이터 생성 함수 호출
iterator = make_iter(0, 10)
print(iterator)
'''
<generator object make_iter at 0x000002A9AE8E6148>
'''

# for문으로 출력
for i in iterator:
    print(i)
'''
0
1
2
3
4
5
6
7
8
9
10
'''

마무리

  • 이번 글에서는 Python에서 함수를 작성하는 방법과 다양한 활용법에대해 다루었음
    • 함수를 정의하는 방법, 함수를 호출하는 방법
    • 함수에 전달할 인수(args)를 설정하는 방법
    • 지역변수와 전역변수의 개념
    • lambda 연산자의 기본적인 사용법
    • 데코레이터와 제너레이터의 기본적인 사용법
  • 이외에도 추가적으로 정리할 내용이 생기면 업데이트할 예정!
  • 다음 글에서는 OOP(객체지향프로그래밍)과 Class에서 대해 다루어 보고자 함
  • 화이팅!
profile
Machine Learning (AI) Engineer & BackEnd Engineer (Entry)

0개의 댓글

관련 채용 정보