함수는 파이썬에 기본으로 포함되어 있는 내장 함수를 사용할 수도 있고, 프로그래머가 직접 정의하여 사용할 수도 있다.
#함수 정의
def 함수명 (매개 변수):
실행할 문장들
return 리턴 값
#함수 호출
함수명(인자)
이 때 매개변수와 리턴 값은 생략될 수도, 하나 이상이 될 수도 있다.
이전 자판기 프로그램의 코드에서 4개의 기능을 함수화 하시오.
<내 코드>
#실습3. 자판기 프로그램 함수화
vending_machine = ['게토레이', '게토레이', '레쓰비', '레쓰비','생수', '생수', '생수', '이프로']
def check_machine():
print("남은 음료수: ", vending_machine)
def is_drink(drink):
return drink in vending_machine
def add_drink(drink):
vending_machine.append(drink)
vending_machine.sort()
return vending_machine
def remove_drink(drink):
vending_machine.remove(minus)
return vending_machine
while True:
check_machine()
#print("사용자 종류를 입력하세요(소비자일 경우 \'소비자\', 또는 숫자 1을, 주인일 경우 \'주인\' 또는 숫자 2를 입력해주세요): \n 1. 소비자 \n 2.주인 \n ")
inning = input("\n사용자 종류를 입력하세요(소비자일 경우 \'소비자\', 또는 숫자 1을, 주인일 경우 \'주인\' 또는 숫자 2를 입력해주세요): \n 1. 소비자 \n 2.주인 \n 3. 종료 \n ")
if inning == "1" or inning == "소비자":
pur = input("마시고 싶은 음료수를 입력하세요: ")
if is_drink(pur):
print(f"{pur} 드릴게요.")
vending_machine.remove(pur)
else:
print(f"{pur}은 지금 없네요.")
elif inning == "2" or inning == "주인":
inning2 = input("원하시는 기능을 선택해주세요. (추가를 원하실 경우 \'추가\' 또는 숫자 0을, 삭제를 원하실 경우 \'삭제\' 또는 숫자 1을 입력해주세요): \n 1. 추가 \n 2. 삭제 \n")
if inning2 == "1" or inning2 == "추가":
check_machine()
plus = input("추가할 음료수를 입력해주세요.: ")
add_drink(plus)
check_machine()
elif inning2 == "2" or inning2 == "삭제":
check_machine()
minus = input("삭제할 음료수를 입력해주세요: ")
if is_drink(minus):
print("삭제 완료")
remove_drink(minus)
check_machine()
else:
print(f"자판기 안에 {minus}가(이) 없습니다. \n")
check_machine()
else:
print("잘못된 입력입니다. (추가를 원하실 경우 \'추가\' 또는 숫자 1을, 삭제를 원하실 경우 \'삭제\' 또는 숫자 2를 입력해주세요): ")
elif inning == '3' or inning == '종료':
print("자판기 프로그램을 종료합니다.")
break
else:
print("잘못된 입력입니다. 소비자일 경우 '소비자', 또는 숫자 1을, 주인일 경우 '주인' 또는 숫자 2를 입력해주세요): ")
전역 변수: 함수, 클래스 외부에 선언하고 영향 범위가 파일 전체
+) 값을 변경하지 않는 상수에 자주 사용된다.
지역 변수: 함수나 명령문(조건, 반복 등)의 블록 안에서 생성되며 블록 {}을 벗어나면 메모리에서 소멸
ex) 함수에 사용되는 매개변수도 지역변수라고 할 수 있다.
동일한 식별자가 지역 변수와 전역 변수로 동시에 존재할 경우:
지역 변수가 전역 변수보다 우위에 있음을 기억하자.
전역 변수를 함수 내에서 읽기만 하는 것은 가능하지만, 변경하는 것은 불가능하다.
-> global 키워드를 이용하면 가능하다!
ex)
x = 0
def oneUp():
global x # 전역 변수 x에 접근하여 값 변경이 가능해짐
x = x + 1
return x
print(oneUp()) #1
print(oneUp()) #2
print(oneUp()) #3
유의할 점:
-이 때 전역 변수가 리스트, 딕셔너리 등 값을 변경하더라도 같은 메모리 위치를 참조하는 변수라면, 함수 내부에서 전역 변수의 수정을 시도해도 오류가 발생하지 않는다.
-만약 변수가 숫자, 문자열, 튜플인 경우 값을 (변경 x) 재할당하면 새로운 메모리 위치를 참조하게 되기 때문에 global 키워드가 필요하게 된다.
함수의 매개변수를 초기화하여 선언하고 함수 호출 시 인수를 생략하면 기존에 입력된 초기 값으로 출력된다.
ex) def 함수이름(변수1, 변수 2 = 상수):
함수의 매개변수는 순서가 중요하다. 인수를 일부 생략한 채 함수를 호출하면 함수 정의 시 먼저 적혀있던 매개변수의 순서대로 함수에 먼저 입력된다.
-> 그러나 이를 순서에 상관 없이 매개변수에 값을 전달하고 싶다면 함수 호출 키워드를 활용하면 된다.
함수 호출 시 매개 변수에 값을 전달할 때 매개변수의 이름을 지정하여 전달하는 방식
-> 순서와 상관 없이 값을 전달할 수 있다!
# 함수 호출 키워드
def intro(name, age, city):
print(f"이름은 {name}이고 나이는 {age}이고 사는 곳은 {city}입니다.")
intro("홍길동", 23, "서울")
intro(city = "서울", name = "임꺽정", age = 23)
intro("홍길동", city = "부산", age = 25)
#키워드 지정이 없는 매개 변수의 값을 먼저 입력할 것! 순서에 맞게 써야 한다.
-가변 위치 매개변수
-매개변수의 개수가 가변적일 때 식별자 앞에 *을 붙여 사용하며 관례상 *args 식별자를 사용
-모든 위치 매개변수를 튜플 형태(변형이 안 되는 리스트)로 묶어서 사용
+)가변 매개변수는 고정 위치 매개변수의 뒤에 있어야 한다.
ex)
def text_def(a, b, *args): #무조건 고정, 1:1 대응인 애들이 앞으로 가고 가변인 애들을 뒤로 빼줘야 한다!
print("test :", a)
print("test :", b)
print("args :", args)
text_def("hi", 1,2,3,4,5) #튜플형태로 나온다
<출력 예시>
test : hi
test : 1
args : (2, 3, 4, 5)
-키워드의 개수가 가변적일 때 사용
-식별자 앞에 **을 표시하며 관례상 **kwargs 식별자를 사용
-모든 키워드 매개변수를 딕셔너리 형태로 묶어서 사용
주의) 반드시 고정 위치 매개변수 - 가변 위치 매개변수 - 가변 키워드 매개변수 순서대로 쓸 것.
ex)
def intro(**kwargs): #가변 키워드 매개변수
for key, value in kwargs.items():
print(f"{key}: {value}")
intro(name = "홍길동", age = 20, city = "Seoul", gender = "female" )
<출력 예시>
name: 홍길동
age: 20
city: Seoul
gender: female
<자주 쓰는 내장함수 예시>
abs(실수): 절댓값을 구하여 출력
pow(x, y): x의 y제곱
square(실수): 실수 제곱
map(함수, 반복 가능한 객체):
리스트의 각 요소에 주어진 함수를 적용하여 새로운 리스트를 반환
-> 결과를 list()로 꼭 변환시켜주어야 한다!
filter(함수, 반복 가능한 객체):
이 때, filter() 안에 들어가는 함수는 True / False 값을 리턴하는 함수가 들어와야 한다.
-> 리스트에서 조건을 만족하는 요소만 필터링하여 반환한다.
-> 결과를 list()로 꼭 변환시켜주어야 한다!
<Tip> map()과 filter() 안에는 간단한 함수만 넣을 것!
1 ~ 30의 자연수 중 특정 수의 배수와 배수의 개수를 계산하는 함수를 정의하시오.
#방법1 # filter() 이용하기
def count(num): #num의 배수로만 이루어진 리스트를 생성하여 반환한다.
lists = [i for i in range(1, 31) if 1 % num == 0]
counts = len(lists)
return lists, counts
num = 3
lists, counts = count(num)
print(f"{num}의 배수: {lists}")
print(f"{num}의 배수의 개수: {counts}")
#방법2
def count(num):
#중첩 함수 - 함수 내에 또다른 함수를 정의한다. 이 함수 내에서만 사용이 가능
def check(x): # 나머지가 0인지 True / False로 반환
return x % num == 0
lists = list(filter(check, range(1, 31)))
return lists, len(lists)
num = 3
lists, counts = count(num)
print(f"{num}의 배수: {lists}")
print(f"{num}의 배수의 개수: {counts}")
함수 안에서 자기 자신을 호출하는 함수
->무한 반복하는 구조이기 때문에 종료 조건이 필요하다.
->반복적인 구조의 간결한 표현에 유리하다.
def func(입력값):
if 조건 (입력값이 충분히 작으면): #종료 조건
return 결과값
else: #더 작은 값으로 호출
return 결과값(func() 호출)
<대표적인 예시 2가지>
def factorial(n):
print("n의 값:", n)
if n == 1:
return 1
else:
return n * factorial(n-1)
print(factorial(3))
결과 예시:
n의 값: 3
n의 값: 2
n의 값: 1
6
def fibonacci(num):
if num == 0:
return 0
elif num == 1:
return 1
else:
return fibonacci(num-1) + fibonacci(num-2)
print(fibonacci(6)) #8
+) 이 방식은 재귀함수의 개념을 설명하기에는 유용하나, 시간 복잡도를 고려한다면 그다지 효율적이지 못한 코딩이라고 한다. 참고해둘 것!
-람다 함수(Lambda Function)는 짧은 익명함수를 작성할 때 사용.
-이름 없이 한 줄로 간단하게 정의할 수 있음.
-def와 return 등의 키워드를 생략한다. (애초에 return 값이 있는 함수이다.)
-변수인데 쓸 때는 함수처럼.
형식: lambda 매개변수: 표현식
def call(func): #매개변수로 함수를 받는 함수
for _ in range(10):
func()
#def 써서 일반적인 함수처럼 정의
def hello():
print("안녕하세요")
#lambda 함수 써서 매개변수 없이 단순 한줄 출력을 하는 것이 더 적합하다.
hello2 = lambda: print("반갑습니다.")
call(hello)
call(hello2)
numbers = [2, 4, 6, 8]
squared = map(lambda x : x ** 3, numbers)
print(list(squared)) #map()의 예시와 비교
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(filter(lambda x: x % 2 ==0, numbers))) #filter()의 예시와 비교