티스토리 뷰
<목차>
파이썬에서의 함수에 대해서 자세히 알아보자!!
<Function vs Method>
<일급 객체(First-class Object)>
파이썬에서 함수는 일급 객체(First-class Object)로 불린다.
C언어에서는 포인터가 일급 객체로 불린다.
<함수를 식별자로 쓸 수 있다.>
함수의 인자로 함수를 넣을 수 있다.
def answer():
print(42)
def run_something(func):
func()
run_something(answer) # answer 함수 객체를 넘긴다.
run_something(answer()) # answer 함수의 반환값을 넘긴다. (None)
함수의 인자로 함수, 그 함수의 인자까지 넣을 수 있다.
def add_args(arg1, arg2):
print(arg1 + arg2)
def run_something_with_args(func, arg1, arg2):
func(arg1, arg2)
def run_something_with_args(add_args, 5, 9)
함수의 인자로 가변 인자를 넣을 수 있다.
def sum_args(*args):
return sum(args)
def run_with_positional_args(func, *args):
return func(*args)
run_with_positional_args(sum_args, 1, 2, 3, 4)
<독스트링(docstring)>
파이썬에서는 가독성을 매우 중요시 여긴다.
함수 바디 시작 부분에 문자열을 포함시켜 함수 정의에 문서를 붙일 수 있다.
<메인함수>
if __name__ == "__main__":
main()
모듈(module)에서 가장 먼저 찾고자 하는 함수 = __main__
클래스(class)서 가장 먼저 찾고자 하는 함수 = __init__
<내부 함수 / 익명 함수>
몰라도 코드 작성 시 문제되는 부분은 없다. 하지만 알아두면 코드를 효율적으로 작성할 수 있다.
내부(inner) 함수
외부 함수의 인수 및 변수를 사용할 수 있다.
반복문이나 코드 중복을 피하고자 사용한다.
def knights2(saying):
def inner2():
return "We are the knights who say : '%S'" % saying
return inner2
파이썬 = 절차형 언어, 선언형 언어
R = 함수형 언어
Programming paradigm - Wikipedia
클로저(closure)
내부 함수가 정의된 스코프에서 외부 함수의 변수를 활용할 수 있다.
함수형 언어에서 나온 기능이다.
- nonlocal
익명 함수(anonymous function, lambda function, lamda expression)
프로그램 내부 루틴의 공간적 요소를 효율적으로 개선 가능하다.
<제너레이터(Generator)>
제너레이터는 시퀀스를 생성하는 객체이다.
함수도 객체다!! 제너레이터도 객체다!!
전체 시퀀스를 한번에 메모리에 생성하고 정렬할 필요 없이, 잠재적으로 아주 큰 시퀀스를 순회할 수 있다.
- 전체를 몰라도 next()를 타고가면서 순회할 수 있다.
return 문으로 값을 반환하지 않고 yield 문으로 값을 반환한다.
- return : 코드 실행의 제어 루틴이 바로 전환된다.
- yield : 비동기 처럼 동작한다. 추가 작업을 할 수 있다.
def my_range(first=0, last=10, step=1):
number = first
while number < last:
yield number
number += step
type(my_range)
Out[3]: function
ranger = my_range(1, 5)
type(ranger)
Out[7]: generator
ranger
Out[9]: <generator object my_range at 0x00000144374B0C80>
ranger 제너레이터의 경우 한번만 사용 가능하다. 한번 순회를 돌고 나면 끝!!
- 다시 사용하고 싶으면 my_range(1, 5)로 다시 만들어 주어야한다.
for x in ranger:
print(x)
1
2
3
4
제너레이터 컴프리헨션
genobj = (pair for pair in zip(['a','b'], ['1', '2']))
genobj
Out[12]: <generator object <genexpr> at 0x00000144374F4200>
for thing in genobj:
print(thing)
('a', '1')
('b', '2')
<데코레이터(decorator)>
하나의 함수를 취해서 또 다른 함수를 반환한다.
- 사용하고 있는 함수를 코드의 수정 없이 변경 가능하게 한다.
- 기존 프로그래밍 언어의 override와 비슷해보이지만 다르게 동작한다.
add_inits 함수를 변경해보자!!
def add_ints(a, b):
return a + b
add_ints(3, 5)
Out[17]: 8
① 데코레이터 생성
def document_it(func):
def new_function(*args, **kwargs):
print(f'Running function: {func.__name__}')
print(f'Positional arguments: {args}')
print(f'Keyword arguments: {kwargs}')
result = func(*args, **kwargs)
print(f'Result: {result}')
return result
return new_function
② 데코레이터 수동 할당 및 실행
cooler_add_ints = document_it(add_ints)
cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
Out[19]: 8
③ 어노테이션을 붙여서 데코레이터를 자동 할당할 수 있다.
@document_it
def add_ints(a, b):
return a + b
add_ints(3,5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
Out[21]: 8
④ 두개의 데코레이터를 동시에 할당할 수 있다.
- def와 가까운 순으로 데코레이터가 실행된다.
def square_it(func):
def new_function(*args, **kwargs):
result = func(*args, **kwargs)
return result * result
return new_function
@document_it
@square_it
def add_inits(a, b):
return a + b
add_inits(3, 5)
Running function: new_function
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 64
Out[24]: 64
- 두 데코레이터의 순서를 바꿀 경우 결과 값은 64로 같지만 그 중간 과정이 바뀐다.
@square_it
@document_it
def add_inits(a, b):
return a + b
add_inits(3, 5)
Running function: add_inits
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
Out[26]: 64
<네임스페이스 / 스코프>
네임스페이스
스코프
클로저를 이해할 경우 4계층으로도 나눠서 생각할 수 있다.
- enclosing scopes
<재귀함수>
대상 함수가 자기 자신을 다시 호출하는 함수이다.
- 함수 종료 구간을 반드시 명시해야한다.
- 문제를 분해할 수 있도록 작성해야한다.
def factorial(n):
if n == 1: # n이 1일 때
return 1 # 1을 반환하고 재귀호출을 끝냄
return n * factorial(n - 1) # n과 factorial 함수에 n - 1을 넣어서 반환된 값을 곱함
print(factorial(5))
120
def hello():
print('Hello, world!')
hello()
hello()
# 종료구간을 설정해주지 않으면 재귀함수가 계속 돌다가 에러를 방생 시킴
RecursionError: maximum recursion depth exceeded while calling a Python object
sys 라이브러리를 이용하여 재귀함수의 제한을 확인할 수 있으며 설정할 수도 있다.
import sys
sys.getrecursionlimit() # get limit
Out[32]: 3000
sys.setrecursionlimit(1500) # set limit
flatten() 함수
"리스트의 리스트"와 같은 복잡한 데이터를 모두 같은 레벨의 리스트로 "평평하게" 만들어준다.
def flatten(lol):
for item in lol:
if isinstance(item, list):
for subitem in flatten(item):
yield subitem
else:
yield item
lol = [1, 2, [3, [4, 5, [6, 7, 8], 9, 10], [11, 12], [13, [14, 15], 16], 17], 18, [19, 20]]
flatten(lol)
Out[40]: <generator object flatten at 0x00000144374B0C10>
list(flatten(lol)) # generator의 값을 확인하고 싶을 경우 list로 바꿔서 사용
Out[41]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
<예외(syntax errors / exceptions)>
일부 언어에서 에러는 특수 함수의 반환값으로 다룬다.
파이썬에서는 예외가 발생할 경우 실행되지 않는다.
short_list = [1, 2, 3]
position = 5
short_list[position]
IndexError: list index out of range
① 에러 처리하기 : try, except
- 두 개 이상의 예외 타입이 발생하면 별도의 예외 핸들러(exept)를 제공하는 것이 가장 좋은 방법이다.
except [에외 타입] as [이름] 으로 예외 객체를 확인할 수도 있다.
short_list = [1, 2, 3]
while True:
value = input("Position [q to quit]?")
if value == 'q':
break
try:
position = int(value)
print(short_list[position])
except IndexError as err:
print(f"Bad index: {position}")
except Exception as other:
print(f"Something else broke: {other}")
Position [q to quit]?>? 1
2
Position [q to quit]?>? 2
3
Position [q to quit]?>? 3
Bad index: 3
Position [q to quit]?>? 4
Bad index: 4
Position [q to quit]?>? d
Something else broke: invalid literal for int() with base 10: 'd'
Position [q to quit]?>? q
② 예외 만들기 : raise
문자열에 대분자가 있을 때 예외를 발생시키는 UppercaseException 예외를 만들 수 있다.
- 예외는 Exceptions 클래스를 상속받는 클래스이다.
class UppercaseException(Exception):
pass
words = ['eenie', 'meenie', 'miny', 'MO']
for word in words:
if word.isupper():
raise UppercaseException(word)
UppercaseException: MO # 우리가 생성한 예외가 발생한다.
③ 예외 처리를 마치고 나면 : finally
ref.
- 2021 청년취업 아카데미 파이썬 수업
'Python' 카테고리의 다른 글
[Python/Flask] DB 제어 명령어 (0) | 2021.07.17 |
---|---|
[Python] secrets 라이브러리 : Generate secure random number (0) | 2021.07.17 |
[Python/Flask] Socket으로 모니터 스크린 공유 (0) | 2021.07.15 |
[Python/Flask] HTTP POST 방식으로 모니터 스크린 공유 (0) | 2021.07.15 |
[Python/Flask] HTTP POST 방식으로 파일 전송 (feat. requests, Flask.request) (0) | 2021.07.14 |