파이썬 파트 5-1. 함수 만들기 및 활용
1. 함수의 기본
함수는 한마디로 ‘코드의 집합’이다.
기본 형태
def 함수 이름(매개변수, 매개변수,..) : # 매개변수가 없어도 무관
문장
# 예시
def print_n_times(value, n):
for i in range(n):
print(value)
print_n_times("hello",5)
cf) 함수 생성시 매개변수를 만들었는데 함수 호출시 매개변수를 넣지 않거나 더 많이 넣으면 TypeError 예외 발생
2. 가변 매개변수
print() 함수와 같이 매개변수를 원하는 만큼 받을 수 있는 함수를 가변 매개변수라고 부른다.
- 가변 매개변수 뒤에는 일반 매개변수가 올 수 없다.
- 가변 매개변수는 하나만 사용할 수 있다.
- 가변 매개변수는 리스트처럼 사용하면 된다.
기본 형태
def 함수 이름(매개변수,매개변수,....,*가변 매개변수) :
문장
예시
def print_n_times(n,*values):
for i in range(n):
for value in values:
print(value)
print_n_times(3,"hello","world","python")
# 출력
hello
world
python
3. 기본 매개변수
print 함수의 자동 완성 기능으로 나오는 설명을 보면
print(value,..., sep='', end='\n', file=sys.stdout, flush=False)
가장 앞에 있는 value가 가변 매개변수이다. 가변 매개변수 뒤에는 일반 매개변수가 올 수 없다. 그런데 특이하게 ‘매개변수 = 값’ 형태로 되어있다. 이는 기본 매개변수라고 하며, 매개변수를 입력하지 않았을 경우 매개변수에 자동으로 들어가는 기본값이다. 기본 매개변수 뒤에는 일반 매개변수가 올 수 없다는 제약이 있다. 따라서 매개변수 순서가 틀리면 TypeError가 발생하니 아래와 같은 형식을 기억해두자.
def 함수(일반 매개변수, 일반 매개변수, 가변 매개변수, 기본 매개변수, 기본 매개변수, ...) # 일반적인 순서를 기억
def 함수(일반 매개변수, 일반 매개변수, 기본 매개변수 , 가변 매개변수)
예시
def print_n_times(value, n=2):
for i in range(n):
print(value)
print_n_times("hello")
# 출력
hello
hello
예시 : 기본 매개변수 변경1
while True:
print(".",end="") # 원래 end="\n" 이라 줄바꿈이 일어나는데 빈 문자열로 바꿔 일어나지 않음
예시 : 기본 매개변수 변경2 : 기본 매개변수값에 덮어씌워진다.
def test(a, b=10, c=100):
print(a+b+c)
test(10,20,30) # 기본 형태 순서대로 대입된다. a=10, b=20, c=30
test(a=10,b=100,c=100) # 매개변수로 대입값을 지정
test(c=10,a=100,b=200) # 입력 순서 상관없이 지정
test(10,c=200) # a=10 b=10 c=200
test(10,"hello",300) # a=10 b="hello" c=300
4. 리턴
값을 반환하는 함수의 결과값을 리턴값이라고 한다. 리턴값이 있으면 리턴값을 반환하면 리턴값 없이 리턴만 있으면 None을 반환
def return_test():
return 100 # 100이 없다면 None이 반환
value = return_test()
print(value) # 100
5. 재귀 함수
재귀적 구현을 파고 들면 끝도 없다. 어떤 함수를 만들 것이라는 의미를 정한 뒤 그 함수를 만들고 그 안에 다시 호출하면 그 기능을 하겠지라고 생각하고 사고를 끝내야한다.
팩토리얼
def fac(n):
if n ==1 :
return 1
return n * fac(n-1)
print(fac(5)) # 120
6. 재귀 함수의 문제 해결: 메모화
재귀 함수는 상황에 따라 같은 것을 기하급수적으로 많이 반복하는 문제가 발생한다. 이 문제를 해결하기 위해 메모화라는 기술을 사용한다.
# 처리가 오래 걸리는 피보나치 수열
def fibo(n) :
if n==1 or n== 2:
return 1
return fibo(n-1) + fibo(n-2)
print(fibo(5))
# 문제를 해결한 피보나치 수열
dic = {1:1, 2:1}
def fibo(n) :
if n in dic:
return dic[n]
output = fibo(n-1) + fibo(n-2)
dic[n] = output
return output
print(fibo(5))
처리가 오래 걸리는 피보나치 수열의 재귀 함수에서는 한 번 구했던 값이라도 처음부터 다시 계산을 하면서 계산 횟수가 기하급수적으로 많아진다. 메모화를 사용해서 했던 계산결과를 딕셔너리에 저장할 경우 했던 계산들은 바로 꺼내서 결과값으로 사용할 수 있다. 따라서 처리 속도가 매우 빨라진다.
7. global 키워드
counter =0
def fibo(n):
counter +=1
if n==1 or n==2 :
return 1
return fibo(n-1)+ fibo(n-2)
print(fibo(5))
# 오류 해결
counter =0
def fibo(n):
global counter # 전역변수 counter을 수정하겠다.
counter +=1
if n==1 or n==2 :
return 1
return fibo(n-1)+ fibo(n-2)
print(fibo(5))
재귀의 횟수를 알아보기 위해 작성한 위 코드를 실행하면 함수안의 counter 에서 밑줄이 표시되면서 Undefined variable 이라고 표시된다. 함수 내에서 전역변수를 사용할 수는 있지만 전역변수를 그냥 수정할 수는 없다. 이를 수정하게 할 수 있도록 해주는 것이 global 키워드이다. 즉, 전역변수를 함수 내에서 수정하기 위해서는 global 변수명
을 사용해야 한다.
참고로 레퍼런스를 나타내는 자료형같은 경우에는 global을 안써도 된다. (딕셔너리 등등) -> 잘 모르겠으면 일단 실행해보고 오류가 나오면 global을 사용한다.
문제 : 재귀 함수를 이용해서 리스트를 평탄화 하는 함수 만들기
def flatten(data) :
output =[]
for i in data:
if type(i) == list:
output += flatten(i)
else :
output +=[i]
# output.append(i)
return output
ex = [[1,2,3],[4,[5,6]],7,[8,9]]
print("원본:",ex)
print("수정:",flatten(ex))
문제 : 한 개의 테이블에 앉을 수 있는 최대 사람수는 10명, 최소는 2명일때 100명의 사람이 하나 이상의 테이블에 나누어 앉는 패턴을 구하시오
## 메모화 이전의 풀이
앉힐수있는최소사람수 = 2
앉힐수있는최대사람수 = 10
전체사람수 = 100
count =0
def fuc(남은사람수, 앉힌사람수):
global count
#탈출조건
if 남은사람수 == 0 :
count +=1
return
if 남은사람수 < 0 : # 1 인경우는 다음 트리로 넘어가면서 0 보다 작은 상태로 넘어감
return
# 재귀함수
for i in range(앉힌사람수,앉힐수있는최대사람수 +1):
fuc(남은사람수-i,i)
return count
print(fuc(전체사람수,앉힐수있는최소사람수))
# 메모화 풀이
앉힐수있는최소사람수 = 2
앉힐수있는최대사람수 = 10
전체사람수 = 100
memo = {} # 메모화 딕셔너리
def fuc(남은사람수, 앉힌사람수):
# 다음과 같은 매개인자가 들어왔을때 메모에 있으면 꺼내쓰기 위해
key =str([남은사람수, 앉힌사람수])
#탈출조건
if key in memo :
return memo[key]
if 남은사람수 == 0 :
return 1
if 남은사람수 < 0 : # 1 인경우는 다음 트리로 넘어가면서 0 보다 작은 상태로 넘어감
return 0
# 재귀함수
count = 0
for i in range(앉힌사람수,앉힐수있는최대사람수 +1):
count += fuc(남은사람수-i,i)
# 메모화
memo[key] = count
return count
print(fuc(전체사람수,앉힐수있는최소사람수))