[혼공학습단 7기] 혼공파 4주차

·2022년 2월 13일
0

파이썬

목록 보기
3/7

05 함수

05-1 함수 만들기

함수의 기본

자자 함수를 만들어봅시다 함수가 어케 생겼는지부터! 보자고요

def 함수이름():
	내용

함수는 이렇게 생겻읍니다.. 이게 함수를 선언하는 거고
이제 이 함수를 만들었으니까 밑에서 써먹어야될 거 아닌교??
그때 호출을 해줘야되는데 호출은 머 다른 언어랑 똑같이

함수이름()

이렇게 호출을 해주면 됩니다리요

함수에 매개변수 만들기

다른 언어랑 똑같이 선언할때 괄호 안에 매개변수를 넣으면 되는!

def 함수이름(매개변수1, 매개변수2):
    print("안녕하세요" + str(매개변수1))
    print("안녕하세요" + str(매개변수2))

함수이름(3,5)

#결과
안녕하세요3
안녕하세요5

아무래도 가장 큰 장점은 매개변수에 어떤 자료형을 넣어도 오류가 안 난다는거?ㅎ 단점이 될 수도 있겠지만..(양날의 검ㅋ) 일단 어어머어어머엄청 작은 프로그램이라 꽤 편함

리턴

와 그리고 파이썬에서 return은 break처럼도 쓰이는구나
함수 안에 return을 넣으면 그 뒤에 있는 명령문 무시하고 호출했던 줄로 돌아가버림..ㅠ 매정해 (이게 break 같은 부분)
다른 언어처럼 return 뒤에 값 넣으면 그 값이 return되는 건 똑같다능

▷선택 미션

가변 매개변수

첨보는 개념이애!

def 함수이름(매개변수1, 매개변수2, *가변매개변수):
    print(매개변수1)
    print(매개변수2)
    print(가변매개변수)

함수이름(0,1,2,3,4,5,6,7,8,9)

#결과
0
1
(2, 3, 4, 5, 6, 7, 8, 9)

1.가변매개변수는 변수명 앞에 *을 붙인다
2.가변매개변수는 함수에 딱 한개씩만 존재할 수 있다
3.가변매개면수는 무조건 맨 뒤에 들어가야한다

기본(디폴트) 매개변수

def print_n_times(value, n=2):
    # n번 반복합니다.
    for i in range(n):
        print(value)

# 함수를 호출합니다.
print_n_times("안녕하세요")

기본 매개변수는 호출할때 값을 입력받아 사용되는게 아니라 함수를 선언할때부터 값을 넣은 매개변수!
1.기본 매개변수는 무조건 맨 뒤에 들어가야한다.
2.'기본 매개변수 = 값' 형태

키워드 매개변수

매개변수에 종류가 세가지를 배웠는데 얘네를 같이 써야될땐

def function(일반매개변수, *가변매개변수, 기본매개변수="값"):
	pass

이 순서로 써주면 된다는 겅미

그리고 만약에 기본 매개변수의 값을 함수 호출할때 바꾸고 싶다!하면 직접 기본 매개변수 이름을 언급해주면됨

function(4,2,7,5,기본매개변수="바꾸고 싶은 값")

이렇게 호출하면
일반매개변수에는 4
가변매개변수에는 (2,7,5)
기본매개변수에는 "바꾸고 싶은 값"이 들어가게 됩니다요

기본매개변수 쓰고 그 다음에 가변매개변수 써도 오류 안 나는 경우

def function(valueA=10, valueB=20, *values):
    print(valueA)
    print(valueB)
    print(values)
function(1,2,3,4,5)

#결과
1
2
(3, 4, 5)

우웅... 그니까 valueA="값" 이렇게 명시해서 바꾸는 거 아니면 기본 매개변수가 가변 매개변수 앞에 와도 되는듯
호출할때 기본 매개변수 값 바꾸고 싶을때 직접 언급은 안 해도 되는듯?
아..ㅡㅡ 잘 모르겠는데 일단 코딩할때 많이 쓰이진 않는다하셨으니까 대충 이해하고 넘어가겠음..ㅎㅎ

print()함수에서 줄바꿈하기 싫을때

print("룰루루", end=" ")

end 키워드를 추가해주는 걸 떠올리면 됨!
end가 print() 함수의 기본 매개변수이걸랑요

▷기본 미션

05-2 함수의 활용

재귀 함수

재귀 함수에서는 팩토리얼이 중요한 개념!
+요즘은 팩토리얼을 고1때 배우는..ㅎ
네네 재귀 함수 고고

def factorial_1(n):
    변수 = 1
    for i in range(1, n+1):
        변수 *= i
    return 변수

def factorial_2(n):
    if n == 0:
        return 1
    else:
        return n * factorial_2(n-1)

print(factorial_1(10))
print(factorial_2(10))

재귀 함수의 문제

허억! 정복하지 못한 피보나치 수열 문제가 나오셧따
오늘 확실히 정리하고 넘어가겠우

*피보나치 수열
1 1 2 3 5 8 13 21 ...

def f(n):
    if n == 1 or n == 2:
        return 1
    else:
        return f(n-1) + f(n-2)

ㅎ 머지 이렇게 간단했었나

counter = 0
def f(n):
    global counter
    counter += 1
    if n == 1 or n == 2:
        return 1
    else:
        return f(n-1) + f(n-2)

print(f(10))
print(counter)

아이고 근데 재귀함수의 가장 큰 단점이 숫자가 커지면 어마무시하게 실행해서 결과값이 늦게 나온다는 거! 예시엔 10을 써놨는데 40만 되도.. 엄청 느려짐

그래서 도대체 얼마나 실행되길래!를 알기 위해서 counter로 카운트해줍니당 여기서 짚고 넘어가야하는거!!!!! 함수 안에서 함수 밖에 있는 변수를 써주려면 global 키워드가 필요햇
함수 안에서

global 변수명

하고 그 변수 쓰시면 되는-

할튼 이런 단점을 보완해주는게 있나니...바로 메모화!

메모화

메모 = { 1:1, 2:1}
def f(n):
    if n in 메모:
        return 메모[n]
    else:
        output = f(n-1) + f(n-2)
        메모[n] = output
        return output

메모 딕셔너리는 global 키워드를 안 써도 되는데 global 키워드는 call by value만 쓰면 되기 때문! call by reference는 안 써주셔도 되는😍😍

조기리턴

메모 = { 1:1, 2:1}
def f(n):
    if n in 메모:
        return 메모[n]
    output = f(n-1) + f(n-2)
    메모[n] = output
    return output

조기 리턴은 그냥 모.. 중간에 return 써서 코드를 더 간략하게 쓸 수 있다 정도?

05-3 함수 고급

튜플

튜플은 리스트와 갱장히 비슷하다고 하시네욧
강사님왈
1.대괄호가 아니라 소괄호로 선언
2.한 번 선언하면 값을 바꿀 수 없음

자자 어떻게 생겼는지 보자구요

a = (1,2,3,4)

머 이렇게 생겼음! 부를때도 리스트랑 똑같이 a[0] a[1] ...이렇게 쓰면 됨 그럼 이제 튜플을 어따가 쓰는지 알아봅세

튜플을 사용하는 경우(1) : 복합 할당

[a, b] = 10, 20
(c, d) = 30, 40

이렇게 쓰면 a,b,c,d 순서대로 각각 10,20,30,40이 들어감
근데 이제 튜플은 괄호가 없어도 됨

[a, b] = 10, 20
c, d = 30, 40

이 된다는 거

튜플을 사용하는 경우(2) : 스왑(swap)

예전에 swap 배울때 a,b=b,a가 된다 언급하고 넘어간 적이 있었는데 오늘 낱낱이. 이해해주겠어

일단 a,b랑 b,a 둘 다 튜플임 정확히는 괄호가 생략된 튜플
(a,b) = (b,a)
이거다 이말이죠! 근데 이것도 뜯어보면 결국엔 공간이 하나 더 쓰인다고 함요미 난 자세히는 모르고..ㅎ 걍 들었었던 기억만이 남아있음

튜플을 사용하는 경우(3) : 튜플을 리턴하는 함수

이게 뭔말이냐면 파이썬엔 함수 종류가 엄청 많잖음! 근데 그 함수 중에서 튜플 자료형을 결과로 내놓는 함수가 있다는 겅미

강사님이 예를 들어주신 함수는 divmod() 함수인데 (몫, 나머지)를 리턴해버림

a, b = 97, 48
몫, 나머지 = divmod(a, b)

그리고 앞에서 enumerate()함수 for문에서 쓸때

for i, value in enumerate([1,2,3,4,5,6]):
	pass

i, value가 튜플이였단 사실..ㄷㄷ 난 걍 변수 두개 선언한줄 ㅠ

for (i, value) in enumerate([1,2,3,4,5,6]):
	pass

원래는 저런 형태인데 괄호를 생략한 형태였던 거!

또또또 완조니 신기한게 있음
return할때 원래 하나의 값만 return해왔잖아여!!! 근데 튜플을 쓰면 여러 개를 return할 수 있음..

def 함수():
	return 10, 20

a,b = 함수()

이렇게하면 두개나 return해버릴 수 있다는고...~~대박적

하나의 요소를 갖는 튜플

요소가 한개인 리스트는 그냥

print([242])

이렇게 써주면 되지만 튜플은..ㅠㅠ 이렇게 안 됨

print((242))

만약에 이렇게 쓰면 튜플이 아니라 그냥 int로 알아버렷

print((242,))

,를 하나 써주면 요소가 한개인 튜플이 쨔란~
하지만 중요한 것... 여기서는 인덱스가 0까지 밖에 없다는거!!
, 들어갔다고 방이 두개라 생각하면 절대 아니아니아니되오

+튜플은 딕셔너리의 key가 될 수 있음! 리스트는 안 됨

콜백함수

예시 코드

def call_10_times(func):
    for i in range(10):
        func(i)

def print_hello(number):
    print("안녕하세요", number)

call_10_times(print_hello)

다른 어떤 함수에서 호출하는 것을 콜백함수라고 함!

람다(lambda)

람다..가 뭐냐면 기능 이름임 근데 이제 좀 더 효율적으로 작성하게 해주는! 그런 기능

def call_10_times(func):
    for i in range(10):
        func(i)

call_10_times(lambda number: print("안녕하세요", number))

아직은 이해가 안 됨 예시 함수 보면서 이해해보겠음ㅎㅎ

1.filter() 함수
일단 filter함수의 매개변수를 봐보자구요

filter(조건 함수, 데이터)

이렇게 생김! 강사님이 보여주신 예시 코드를 나도 한 번...쳐보겠음ㅎㅎ

def 짝수만(number):
    return number % 2 == 0

a = list(range(100))
b = filter(짝수만, a)
print(list(b))

이 코드를 분석해보자면 우선 a리스트에는 0부터 99까지 있는 상태
b에서 filter 함수로 a리스트의 데이터들을 짝수만 함수의 매개변수로 들어가서 return된 값(리스트)들이 b리스트로 들어가게 되는 거!

그래서 저 코드를 실행 하면 [0, 2, 4, 6, ..., 98] 이렇게 나옴!

여기에 lambda 키워드를 쓰게되면

a = list(range(100))
b = filter(lambda number: number % 2 == 0, a)
print(list(b))

!!!!!!!!!!직접 해보니까 이해가 되기 시작

짝수만 = lambda number: number % 2 == 0

a = list(range(100))
b = filter(짝수만, a)
print(list(b))

오호...이렇게 lambda를 변수 안에 넣어서 써도 된다능

2.map() 함수
예전에 형변환하면서 봤던 함수인데 뭔가 내 기억과는 다른 쓰임새라서 조금 당황당황ㅋ map() 함수는 새로운 리스트를 만들어주는 함수래여~~

def 제곱(number):
    return number * number

a = list(range(100))
print(list(map(제곱, a)))

얘는 lambda 키워드 쓰는 거 혼자 해볼게요미

a = list(range(100))
print(list(map(lambda number: number * number, a)))

리스트 내포랑도 비슷한 기능이애
*리스트 내포 복습

print([i*i for i in a if i % 2 == 0])

파일 처리

C언어 fopen이 생각나잔앗!
python에서는 그냥 open()을 해주면 됨!

file = open()
file.close()

그리고 잠깐 짚고 넘어갈 것이 있습니다요
-w : write 모드(새로 쓰기 모드)
-a : append 모드(뒤에 이어서 쓰기 모드)
-r : read 모드(읽기 모드)
네넹 이러 기억하고 넘어가기

file = open("test.txt", "w")

이렇게 open 함수 매개변수로 ("텍스트 파일명", "모드")을 넣으면 됨
저렇게 해주면

file.write("안녕하세요.")

이런 함수를 쓸 수 있게 됨!

요래요래 해주면 최종적으로

file = open("test.txt", "w")
file.write("안녕하세요.")
file.close()

이런 코드가 완성되는데 실행시켜주면

오모오모~~ txt 파일이 생겼읍니다~

...근데 깨져버리셨음 인코딩을 utf8로 바꿔야될듯
구글링해보니까 두가지 방법이 나옴
1. 메모장을 실행해서 직접 인코딩을 utf8로 바꾼 후 저장시킨다
2. open() 매개변수에 encoding="UTF-8"을 추가한다

2의 방법으로 해보겟음ㅎㅎ

file = open("test.txt", "w", encoding = "utf-8")
file.write("안녕하세요.")
file.close()

이렇게 했더닝..

쨘 안 깨지고 잘 됨

그리고 r모드로 다시 open하면 출력창에도 출력할 수 있음!

file = open("test.txt", "w", encoding = "utf-8")
file.write("안녕하세요.")
file.close()

file = open("test.txt", "r", encoding = "utf-8")
print(file.read())
file.close()

다만 print() 함수 안에 넣어줘야 출력이 된다는 거!
..그리고 자동으로 close를 호출해주는 구문도 있음
파이썬 너 도대체 뭐니....~~ 효자언어

#before
file = open("test.txt", "w", encoding = "utf-8")
file.write("안녕하세요.")
file.close()

#after
with open("test.txt", "a", encoding = "utf-8") as file:
    file.write("안녕하세요.")
#before
file = open("test.txt", "r", encoding = "utf-8")
print(file.read())
file.close()

#after
with open("test.txt", "r", encoding = "utf-8") as file:
    print(file.read())

직접 써보면서 이해를 했는데 with를 어떻게 쓰는지! 한글로 다시 정리해볼게요미

#before
변수명 = open("경로","모드")
명령문
변수명.close()

#after
with open("경로","모드") as 변수명:
	명령문

네넹~~~쉬움

제너레이터

제너레이터는 "이터레이터를 직접 만들 때 사용하는 구문"이라고 하심...! yield 키워드가 들어가면 제너레이터가 된다고..욧...네...실습부터 해보고 이해해보잣

우선 여기 함수 하나가 있습니다요

def 함수():
	print("출력A")
    print("출력B")
    
함수()

#결과
출력A
출력B

근데 함수()안에 yield 키워드를 하나 추가하게 되면

def 함수():
	print("출력A")
    print("출력B")
    yield
    
함수()

#결과

제너레이터 함수가 되고 기본적으로 아무것도 출력되지가 않게 됨
얘를 출력하고 싶다!하면 밑의 코드처럼 해주면 됨

def 함수():
    print("출력A")
    print("출력B")
    yield

제너레이터 = 함수()

next(제너레이터)

흠...아직 1도 이해 안 감
그리고 next(제너레이터)은 100이라는 값을 가지고 있음

이제 yield가 도대체 뭘 양보하는지! 알아보자고

def 함수():
    print("출력A")
    yield 100
    print("출력B")
    yield 200
    print("출력C")
    yield 300
    print("출력D")
    yield 400

제너레이터 = 함수()

next(제너레이터)

이렇게 하면 결과값이

출력A

만 나오게 되는데 next(제너레이터)를 추가하게 된다?!하면
그 밑에 출력B,C,D도 다 출력이 됨

def 함수():
    print("출력A")
    yield 100
    print("출력B")
    yield 200
    print("출력C")
    yield 300
    print("출력D")
    yield 400

제너레이터 = 함수()

next(제너레이터)
next(제너레이터)
next(제너레이터)
next(제너레이터)
#결과
출력A
출력B
출력C
출력D

그래서 for문이랑 조합해서 쓰는 경우도 있다고 함!

def 함수():
    print("출력A")
    yield 100
    print("출력B")
    yield 200
    print("출력C")
    yield 300
    print("출력D")
    yield 400
    
#next 빼고

for i in 제너레이터:
	print(i)

이렇게 하면

출력A
100
출력B
200
출력C
300
출력D
400

요렇게 다 출력이 됨
근데 저기서 for문을 한 번 더 돌린다해도 출력A~400이 한 번 더 출력되지는 않음
=> 일회용 함수다!

제너레이터를 쓰는 경우가 몇가지 더 있는데 그거는 이 책의 범위를 뛰어넘는다고 함ㅎ 일단은 메모리 절약을 위해서 쓴다고 보면 될듯! 미래의 내가 더 공부해주겠지 모 ㅋ

확인문제 1번

1::2::3::4::5::6
을 출력하라고 하심!

numbers = [1,2,3,4,5,6]

print("::".join(
    map(str, numbers)
))

map함수로 numbers를 str로 형변환시켜주면 됨!~~

확인문제 2번

numbers = list(range(1, 10+1))

print("#홀수만 추출하기")
print(list(filter(lambda number: number % 2 != 0 ,numbers)))
print()

print("# 3이상, 7미만 추출하기")
print(list(filter(lambda number: 3<=number<7,numbers)))
print()

print("# 제곱해서 50 미만 추출하기")
print(list(filter(lambda number: number ** 2 < 50, numbers)))

쨘ㅋ lambda 완벽 이해

포스팅 끝!

profile
기록하고 싶은 내용들을 주로 올리고 있습니다

0개의 댓글