[패스트캠퍼스] 파이썬 초격차 패키지 Part1-(3~5)

다히·2023년 3월 4일
0

Python

목록 보기
3/3

Part1의 1, 2는 환경설정이므로 생략

1-03 인코딩과 디코딩

  • 인코딩 = 코드화 = 암호화 = 부호화
  • 디코딩 = 역코드화 = 복호화
a = "한글"
b = a.encode('utf-8')
b.decode('utf-8')  # 인코딩과 맞춰야 함

소스코드의 인코딩과 디코딩

  • 2.x 버전은 ascii
  • 3.0 부터는 utf-8
    -> 다른 사람을 위해 코드 첫 줄에 아래와 같이 인코딩 명시해주면 좋음
    # -*- coding: utf-8 -*-

1-04. 클로저와 데코레이터

클로저 Closure

함수 안의 함수를 결과로 반환할 때, 그 내부 함수를 클로저라고 함

<사용되는 곳>

  • 콜백 함수

  • 함수의 순차적 실행

  • 데코레이터 함수

예제

받은 수에 n을 곱하고 싶을 때 mul3 mul4.. 함수를 각각 만들기 비효율적

방법1. 클래스 사용

class Mul:
	def __init__(self, m):
    	self.m = m
    
    def mul(self, n):
    	return self.m * n
	
    def __call__(self, n):  # mul 함수를 __call__ 함수명으로 변경
    	return self.m * n
    

if __name__ == "__main__":
	mul3 = Mul(3)
    mul5 = Mul(5)
    
    print(mul3.mul(10))
    print(mul5.mul(10))
    
    print(mul3(10))
    print(mul5(10))

방법2. 클로저 사용

def mul(m):  # 외부 함수
	def wrapper(n):   # 내부 함수 [클로저]
    	return m * n
    return wrapper
    
if __name__ == "__main__":
	mul3 = Mul(3)  # m = 3인 wrapper 함수가 mul3에 저장
    print(mul3(10))  # m = 3, n = 10인 wrapper 함수가 실행     

데코레이터 Decorator

  • 함수를 꾸며주는 함수

  • 함수를 인수로 받는 클로저

  • @을 이용한 어노테이션으로 사용

<사용되는 곳>

  • 반복되는 작업을 여러 함수에 적용할 경우 ex) 로그 남기기 등

  • 기존 함수를 수정하지 않고 추가 기능을 구현하고 싶을 경우

예제

func1, func2 함수의 내용이 중간 값 val만 다르고 다 동일함

함수 각각 정의하는 경우

import time

def func1(a, b):
	start = time.time()
    print("함수 실행")
    
    val = a + b
    
    end = time.time()
    print("실행 시간: %f 초" % (end - start))
    
    return val
    
def func2(a, b):
	start = time.time()
    print("함수 실행")
    
    val = a * b
    
    end = time.time()
    print("실행 시간: %f 초" % (end - start))
    
    return val

↓ 데코레이터 만들기

import time

def func1(a, b):
	val = a + b
    return val

def func2(a, b):
	val = a * b
    return val

# 실행 시간 측정 데코레이터
def elapsed(func):
	def wrapper(a, b):
    	print("함수 실행")
        start = time.time()
        result = func(a, b)
        end = time.time()
        print("실행 시간: %f 초" % (end - start))
        return result
    return wrapper
    
    
if __name__ == "__main__":
	deco1 = elapsed(func1)
    deco2 = elapsed(func2)
    print(deco1(1, 2))
    print(deco2(1, 2))

@ 활용

import time

def elapsed(func):
    def wrapper(a, b):
        print("함수 실행")
        start = time.time()
        result = func(a, b)
        end = time.time()
        print("실행 시간: %f 초" % (end - start))
        return result
    return wrapper

@elapsed
def func1(a, b):
    val = a + b
    return val

@elapsed
def func2(a, b):
    val = a * b
    return val


if __name__ == "__main__":
    print(func1(1, 2))

1-05 이터레이터와 제너레이터

이터레이터 Iterator

  • 집합에서 값을 차례대로 꺼낼 수 있는 객체(Object)

  • for문을 순회할 수 있는 객체

  • 반복 가능 (iterable) 객체에만 사용 가능

    • iter()로 반복 가능 객체 변환
    • next()로 다음 값 뽑기
  • 한 번 반복하면 다시 사용할 수 없음


예제

for a in [1, 2, 3]: 
	print(a)

↓ 이터레이터 만들기

a = [1, 2, 3]
iterator = iter(a)  # 반복 가능 객체 변환
print(type(iterator))  # list_iterator

print(next(iterator))  # 원소 출력

for a in iterator:
	print(a)    
  • next(iterator)의 경우

    3번 호출까지는 차례로 1, 2, 3 출력되고

    4번째 호출 시, iterator 내의 모든 원소를 순회했으므로 StopIteration 에러 발생

  • next(iterator)를 원소 개수만큼 호출한 후에 for문으로 iterator을 순회하려 하면,

    한 번 반복 후에는 재사용이 불가능하다는 특징에 의해 아무것도 출력되지 않음

    다시 사용하고 싶으면 iterator 다시 선언해줘야 함


제너레이터 Generator

  • 이터레이터를 생성해주는 함수

  • 함수가 하나의 고정된 값을 반환하는 것이 아닌 순차적으로 다른 값을 반환하기 원할 때

    (상황마다 리턴 값이 다르고 싶을 때 / 리턴하는 시점을 다르게 하고 싶을 때 등)

  • yield()

기본 사용법

def generator():
	yield 'a'
    yield 'b'
    yield 'c'
    
g = generator()
print(type(g))  # generator 

print(next(g))  
  • 이터레이터와 마찬가지로 print(next(g))

    첫 번째 호출 -> 'a', 두 번째 호출 -> 'b', 세 번째 호출 -> 'c'

    네 번째 호출 -> StopIteration 에러 발생

예제

번호표 받는 식당, 자리 날 때마다 몇 번 고객 입장하세요 안내 하기

def client_count(total_client):
	n = 1
    for num in range(total_client):
    	print(f"{n} 번째 고객님 입장하세요.")
        n += 1
        yield
        
mygen = client_count(100)
next(mygen)  # 호출 시마다 차례로 'n 번째 고객님 입장하세요' 출력됨
  • 이때는 print문이 안에 있고 yield 뒤에는 아무것도 없으므로,

    print(next(mygen)) 하게 되면 출력문 출력된 뒤 None까지 출력됨

0개의 댓글