728x90
반응형

주제 : 회원전용 도서관리 프로그램 작성하기

<요구 사항>
📍최초 메뉴
       : 회원 번호는 문자열 무엇이든 상관없이 등록
       : 서비스 종료시 프로그램 자체 종료
 [서비스 이용을 위한 회원 인증]
  1. 회원번호 등록
  2. 회원 인증
  3. 서비스 종료

📍회원 인증이 된 경우 메뉴
       : 도서 정보 - 도서번호, 도서제목, 재고권수
       : 도서 상태 확인 - 특정 도서에 대한 정보 조회(도서번호, 도서제목, 현재권수/전체권수)
 [도서 서비스 메뉴]
  1. 도서 입고
  2. 도서 대출
  3. 도서 반납
  4. 도서 상태 확인
  5. 도서 전체 목록 확인
  6. 도서 서비스 종료(회원 인증 메뉴로 갑니다.)

 

 

내가 만든 코드

1. class LibraryKiosk 생성

class LibraryKiosk :
    def __init__(self) :
        self.books = {}

    def add_book(self, book_id, title, quantity) :
        if book_id in self.books : 
            self.books[book_id]["quantity"] += quantity
            self.books[book_id]["register_quantity"] += quantity
        else :
            self.books[book_id] = {"title" : title, "quantity" : quantity, "register_quantity" : quantity}
        print(f"도서번호 : {book_id} / 제목 : {title} / 입고수량 : {quantity} 입고성공😍")

    def borrow_book(self, book_id):
        if (book_id in self.books) and (self.books[book_id]['quantity']) > 0 :
            self.books[book_id]['quantity'] -= 1
            print("대출이 완료되었습니다.")
            print(f"도서번호 : {book_id} / 제목 : {self.books[book_id]['title']} / 남은재고수량 : {self.books[book_id]['quantity']}")
        else:
            print("도서가 존재하지 않거나, 대출할 재고가 없습니다.")

    def return_book(self, book_id) :
        if book_id in self.books and (self.books[book_id]["register_quantity"] - self.books[book_id]["quantity"]) > 0 :
            self.books[book_id]["quantity"] += 1
            print(f"도서번호 : {book_id} / 제목 : {self.books[book_id]['title']} / 남은재고수량 : {self.books[book_id]['quantity']}")
        else:
            print("해당 도서가 존재하지 않습니다.")

    def check_book(self, book_id) :
        if book_id in self.books :
            (print(f"도서번호 : {book_id} / 제목 : {self.books[book_id]['title']} / 현재수량 : {self.books[book_id]['quantity']} / 전체수량 : {self.books[book_id]['register_quantity']}"))
        else:
            print("해당 도서가 존재하지 않습니다.")

    def list_book(self):
        for i in self.books.keys():
            print(f"{self.books[i]['title']}")

 

2. bookKiosk 함수 생성

def bookKiosk(register_num, customer) :
    if register_num in customer :
            kiosk = LibraryKiosk()
            while True :
                choice = input("""
                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                               """)
                
                if choice == "1" :
                    print("도서 입고")
                    book_id = input("도서 번호를 입력해 주세요 : ")
                    title = input("도서 제목를 입력해 주세요 : ")
                    quantity = int(input("입고할 권수를 입력해 주세요 : "))
                    kiosk.add_book(book_id, title, quantity)
                    
                elif choice == "2" :
                     print("도서 대출")
                     book_id = input("대출할 도서번호를 입력해주세요 : ")
                     kiosk.borrow_book(book_id)
                    
                elif choice == "3" :
                     print("도서 반납")
                     book_id = input("반납할 도서번호를 입력해주세요 : ")
                     kiosk.return_book(book_id)
                    
                elif choice == "4" :
                     print("도서 상태 확인")
                     book_id = input("확인할 도서번호를 입력해주세요 : ")
                     kiosk.check_book(book_id)
        
                elif choice == "5" :
                     print("도서 전체 목록 확인")
                     kiosk.list_book()
                
                elif choice == "6" :
                    print("도서 서비스 종료(회원 인증 메뉴로 돌아갑니다.)")
                    break
                else :
                    print("다시 선택해주세요")
    else :
        print("등록되지 않은 회원입니다.")

 

3. main 함수 생성

def main() :
    customer = []
    while True : 
        choice = input("""
                        <서비스 이용을 위한 회원 인증>
                        1. 회원번호 등록
                        2. 회원 인증
                        3. 종료
                        원하는 번호(1~3)를 선택하세요
                        """)
    
        if choice == "1" :
            print("회원번호 등록")
            user_num = input("등록할 회원번호를 입력해주세요: ")
            
            customer.append(user_num)
               
        elif choice == "2" :
            print("회원 인증")
            register_num = input("등록하신 회원번호를 입력해주세요 : ")
            bookKiosk(register_num, customer)
                                                                                              
        elif choice == "3" :
            print("종료")
            break
            
        else :
            print("다시 선택해주세요")

if __name__ == "__main__":
    main()

 

4. 결과

 <서비스 이용을 위한 회원 인증>
                        1. 회원번호 등록
                        2. 회원 인증
                        3. 종료
                        원하는 번호(1~3)를 선택하세요
                         1
회원번호 등록
등록할 회원번호를 입력해주세요:  001

                        <서비스 이용을 위한 회원 인증>
                        1. 회원번호 등록
                        2. 회원 인증
                        3. 종료
                        원하는 번호(1~3)를 선택하세요
                         2
회원 인증
등록하신 회원번호를 입력해주세요 :  001

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                1
도서 입고
도서 번호를 입력해 주세요 :  001
도서 제목를 입력해 주세요 :  파이썬
입고할 권수를 입력해 주세요 :  5
도서번호 : 001 / 제목 : 파이썬 / 입고수량 : 5 입고성공😍

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                2
도서 대출
대출할 도서번호를 입력해주세요 :  001
대출이 완료되었습니다.
도서번호 : 001 / 제목 : 파이썬 / 남은재고수량 : 4

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                3
도서 반납
반납할 도서번호를 입력해주세요 :  001
도서번호 : 001 / 제목 : 파이썬 / 남은재고수량 : 5

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                4
도서 상태 확인
확인할 도서번호를 입력해주세요 :  001
도서번호 : 001 / 제목 : 파이썬 / 현재수량 : 5 / 전체수량 : 5

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                5
도서 전체 목록 확인
파이썬

                               <도서 서비스 메뉴>
                               1. 도서 입고
                               2. 도서 대출
                               3. 도서 반납
                               4. 도서 상태 확인
                               5. 도서 전체 목록 확인
                               6. 도서 서비스 종료(회원 인증 메뉴로 돌아갑니다)
                               원하는 번호(1~6)를 선택하세요.
                                6
도서 서비스 종료(회원 인증 메뉴로 돌아갑니다.)

                        <서비스 이용을 위한 회원 인증>
                        1. 회원번호 등록
                        2. 회원 인증
                        3. 종료
                        원하는 번호(1~3)를 선택하세요
                         3
종료

 

728x90
반응형
728x90
반응형

실습 1

전화번호를 전달받아서, 뒤 4자리를 제외하고 나머지 별(*)로 표시하는 함수 만들어서 출력하기
- 함수명 : solution
- 예시 : 010-1234-5678 ==>*******5678

 

내가 만든 코드

def solution(phone_number) :
    new_number = '*' * (len(phone_number) - 4) + phone_number[-4:]
    return new_number
    
solution("010-1234-5678")

 

'********5678'

 

강사님 코드

def solution_t(phone_number) :
    new_number = '*' * len(phone_number[:-4]) + phone_number[-4:]
    return new_number

solution_t("010-1234-5678")

 

'********4567'

실습 2

연속된 정수 데이터 제거하기
 - 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하기
 - 단, 제거된 후 남은 숫자들은 원본 데이터 타입으로 출력하기
 - 함수명 : solution
 - 예시 : [1, 1, 3, 3, 0, 1, 1] ===> [1, 3, 0, 1]

 

내가 만든 코드

def solution() :
    list = [1, 1, 3, 3, 0, 1, 1]
    new_list = []
    for i in range(len(list)) :
        if i == 0 or list[i] != list[i - 1] :
            new_list.append(list[i])           
    return new_list

solution()

 

[1, 3, 0, 1]

 

강사님 코드

def solution_t(num_list) :
    rs_list= []
    last_num = -1
    
    for i in num_list :
        if i == last_num :
            continue
            
        rs_list.append(i)    
        last_num = i
        
    return rs_list

solution_t([1, 1, 3, 3, 0, 1, 1])

 

[1, 3, 0, 1]
728x90
반응형
728x90
반응형

정규표현식(Regular_Expression)


<정규표현식 패턴>

- 대괄호 [] : 대괄호 안에 있는 문자 중에 하나라도 매치되면 추출
- 점(.) : 앞뒤 문자의 사이에 보통 주로 사용함. 하나의 문자를 의미함
            예시 : a.c의 패턴인 경우 "abc", "abc"....
- 반복(*) : 앞의 문자가 0번 이상 반복될 때 추출
                예시 : ab*c의 패턴인 경우 "ac", "abc", "abcd", "abbbbbbbbbbc"....
- 반복(+) : 앞의 문자가 1번 이상 반복 될 때 추출
                예시 : ab+c의 패턴인 경우 "abc", "abbc", "abbbbbc"...
- 반복({m, n}) : 앞의 문자가 최소 m번, 최대 n번 반복될 때 추출 됨
                          예시 : a{2, 4}의 패턴인 경우 "aa", "aaa", "aaaa"....
- 시작(^)과 끝($) : 각 문자열의 시작과 끝을 나타냄
                                예시 : ^abc의 패턴인 경우 "abc"로 시작하는 문자열에 대해 추출
                                 예시 : $abc의 패턴인 경우 "abc"로 끝나는 문자열에 대해 추출
- 물음표(?) : 바로 앞의 문자가 0 또는 1회 나타날 수 있음을 의미함
                      예시 : a?의 패턴인 경우 "a" 또는 ""일 경우 추출함
- 역슬래시(\) = 이스케이프라고 읽음 : 특수문자를 일반 문자로 인식하게 함
- 소괄호() = 그룹화라고 읽음 : 괄호 안의 패턴을 하나의 그룹으로 묶어서 처리가능
                                                    예시 : (abc)+의 패턴인 경우 "abc", "abcabc", "abcabcabc"....
- [0-9] : 0에서 9까지의 숫자중 하나
- [!@#$%^&*(),.?";{}|<>] : 특수 기호 중 하나
- [ㄱ-ㅎㅏ-ㅣ가-힣] : 한글 중 하나
- [a-zA-Z] : 알파벳 소문자 또는 대문자 중 하나
- \d : 숫자 중 하나
- \b : 단어의 경계를 나타냄(보통 문장의 처음과 끝에 제시)
→ 위의 패턴들은 조합해서 사용 가능

정규표현식 쓰기 위해 라이브러리 불러오기

import re

 

 "abcdefg" 문자열에서 ade에 대한 문자만 추출하기

- r은 패턴을 인식시켜주는 역할

- findall : 임의 문자열에서 패턴에 맞는 값을 모두 찾아서 리스트 타입으로 반환한다.

text = "abcdefg"

### 추출할 패턴 정의하기
pattern = re.compile(r"[ade]")

### text 문자열에서 패턴에 맞는 값만 추출하기
rs_text = pattern.findall(text)
print(rs_text)
['a', 'd', 'e']

 

점(.) 패턴을 이용하기

- 문자열 "abcdef afceeeazc"에서 a로 시작해서 c로 끝나는 3단어 추출하기
- 출력 예시 : [abc, afc, axc]

text = "abcdef afceeeazc"
pattern = re.compile(r'a.c')

rs_test = pattern.findall(text)
print(rs_test)
['abc', 'afc', 'azc']
728x90
반응형
728x90
반응형

<제너레이터(Generator)>

📍이터레이터는 class 기반, 제너레이터는 함수 기반

📍함수를 이용해서 이터레이터(반복)의 기능을 구현

📍이터레이터와 동일하게 호출 시점에만 메모리를 사용하고 사용이 끝나면 소멸된다.

📍반환할 때 사용하는 명령어는 return이 아닌, yield를 사용한다.

📍이터레이터와 동일하게 전체 또는 next() 한건씩 출력 가능하다.

 

제너레이터 기본 문법

def simple_generator() :
    ### 첫번째 반환할 값
    yield 1

    ### 두번째 반환할 값
    yield 2

    ### 세번째 반환할 값
    yield 3

 

제너레이터 전체 출력하기

- 제너레이터에서는 수를 객체러 인지하고 사용한다.
- 함수를 생성한다는 의미 또는 제너레이터 객체를 생성한다는 의미를 사용한다.

for v in simple_generator() :
    print(v)
1
2
3

1부터 5까지의 숫자를 생성해서 반환하는 제너레이터 만들기

def number_generator() :
    for i in range(1, 6, 1) :
        yield i

 

전체 출력하기

- 함수 객체 생성하기

gen = number_generator()
for num in gen :
    print(num)
1
2
3
4
5


한건씩 출력하기

### - 함수 객체 생성하기
gen = number_generator()
try:
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
except:
    pass
1
2
3
4
5

※ try / except 가 없다면 오류 발생

파일 한줄씩 읽어서 반환하는 제너레이터 만들기

read_lines 함수 생성

- 파일처리 시 이터레이터와 다르게, with문을 사용해도 된다.

def read_lines(file_path) :
    with open(file_path, "r", encoding="utf-8") as file :
        for line in file :
            yield line.strip()

 

 

제너레이터 함수 생성하기

gen = read_lines("./04_example.txt")
for line in gen :
    print(line)

 

- 메모장 내용과 주피터 노트북 실행 결과

가가가
나나나
다다다
라라라

 

728x90
반응형
728x90
반응형

<이터레이터(Iterator)>

📍파이썬에서 반복 가능한 객체(클래스)를 표현하는 데 사용되는 인터페이스

📍이터레이터는 init() 함수와 next() 함수를 이용하여 반복(Iterator)을 수행함

📍__iter__() 메서드 

iter 메서드는 이터레이터 객체 자체를 반환한다. 이터레이터 객체는 __iter__() 메서드를 가지고 있어야 한다. 이는 파이썬에서 "순회 가능한(iterable)" 객체의 특징이다.

📍__next__() 메서드

next 메서드는 다음 요소를 반환한다. 만약 더 이상 반환할 요소가 없으면 StopIteration 예외를 발생시켜 순회를 종료시킨다. 이 메서드가 호출될 때마다, 다음 요소를 반환하고 내부 상태를 업데이트하여 다음 호출 시에 이전 요소의 다음 요소를 반환할 수 있도록 한다.

 

반복문 사용하여 이터레이터 사용하기

### 클래스 정의하기

- 아래 코드는 MyIterator 클래스를 정의하고 객체를 생성한 후, for 루프를 사용하여 이터레이터를 순회하고 있다. 이터레이터 객체를 생성하면 __init__ 메서드가 호출되고, 그 후에 __iter__ 메서드가 호출되어 이터레이터 객체를 반환한다. 그리고 for 루프에서 각 단계마다 __next__ 메서드가 호출되어 반복이 수행된다. 반복이 끝나면 StopIteration 예외가 발생하여 순회가 종료된다

### 클래스 정의하기
class MyIterator :
    ### 클래스 생성자 정의하기
    def __init__(self) :
        self.current_value = 0
        print(f"#1 (__init__) : self={self} / self.current_value={self.current_value}")

    ### 자신의 클래스를 반환하는 iter 함수 정의
    def __iter__(self) :
        print(f"#2 (__iter__) : self={self}")
        return self

    ### 반복을 수행하는 next 함수 정의
    def __next__(self) :
        print(f"#3 (__next__) : self={self}")
        ### current_valu의 값이 5보다 작을 때까지 반복 수행
        if self.current_value < 5 :
            # - 반환할 변수에 current_value의 현재값 저장
            result = self.current_value
            # - result 값 반환
            self.current_value += 1

            print(f"#4 : result={result} / self.current_value={self.current_value}")
            # - return 값 반환
            return result
        else :
            print("#5 : StopIteration 예외 발생")
            ### 이터레이터는 반복이 끝나면 종료시켜야함
            # - 종료시키는 방법은 강제로 오류 발생시킴
            raise StopIteration

 

### 이터레이터 실행시키기

- 클래스 생성하기

my_iterator = MyIterator()
#1 (__init__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510> / self.current_value=0

 

### 반복문 실행시키기

- 이터레이터 기능은 반복문(for or while)을 사용해야만 작동하는 기능임

- 최초 __iter__() 함수를 호출하고, 출력 시 __next__() 함수가 한 번씩 수행하면서 값을 반환받아서 출력함

- 한번 반환된 후 메모리는 초기화되며, 다음 반복 시 다시 메모리 사용

- 메모리를 효율적으로 활용할 수 있음

- 반복 수행하여 result 값 출력하기

for value in my_iterator :
    print(value)
#2 (__iter__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=0 / self.current_value=1
0
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=1 / self.current_value=2
1
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=2 / self.current_value=3
2
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=3 / self.current_value=4
3
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=4 / self.current_value=5
4
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#5 : StopIteration 예외 발생

반복문 사용하지 않고 이터레이터 실행시키기

### 이터레이터 실행시키기

- 클래스 생성하기

my_iterator = MyIterator()
#1 (__init__) : self=<__main__.MyIterator object at 0x0000014EF601D110> / self.current_value=0

 

### 반복문 사용하지 않고 실행시키기

print(next(my_iterator))
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF5348E50>
#4 : result=0 / self.current_value=1
0

 

### try / except로 예외처리

try : 
    print(next(my_iterator))
    print(next(my_iterator))
    print(next(my_iterator))
    print(next(my_iterator))
except :
    print("이터레이터 종료")

 

- 처음 실행 했을 때 결과

3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=1 / self.current_value=2
1
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=2 / self.current_value=3
2
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=3 / self.current_value=4
3
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=4 / self.current_value=5
4

 

- 두 번 실행했을 때 결과

#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF601D110>
#5 : StopIteration 예외 발생 이터레이터 종료

간단 실습

### 이터레이터 클래스 생성해서 Hello 각 단어 출력하기

- 클래스 이름 : StringIterator

- 임의 문자열을 받아서 처리한다.

- 임의 문자열은 외부에서 클래스 생성 시 넣어준다.

 

내가 만든 코드

class StringIterator:
    def __init__(self, word):
        self.word = word
        self.index = 0

    def __iter__(self):
        return self 

    def __next__(self):
        if self.index < len(self.word):
            result = self.word[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration

 

 

- 코드실행

string_iter = StringIterator("안녕하세요")
for v in string_iter:
    print(v)




 

강사님 코드

- p_text 지역변수, 매개변수로써의 의미

- self.text 는 멤버 변수

- 둘이 저장되는 위치가 다름

class StringIterator_:
    ### 클래스 생성자
    def __init__(self, p_text) :
        # - next 함수에서 1씩 증가시키면서 반복 조건에 사용할 변수
        self.index = 0

        # - 받아온 문자열
        self.text = p_text

    ### 반복수행을 위한 iter 함수 정의
    def __iter__(self):
        return self 

    ### 한건 한건 처리를 위한 next 함수 정의
    def __next__(self) :
        if self.index < len(self.text) :
            ### 문자열에서 문자 하나씩 추출하기
            result = self.text[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration

 

 

- 코드 실행

### 이터레이터 기능 사용하기
# 반복문을 이용해서 추출하기
# - 클래스 생성하기
msg = "Hello"
string_iter_ = StringIterator_(msg)

 

 

- 반복문을 이용해서 전체 추출하기

for char in string_iter_ :
    print(char)
H
e
l
l
o

 

- 따로따로 실행하기

print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
H
e
l
l
o

※ 예외처리를 안 했기 때문에 한번 더 실행하면 오류 발생

일반 프로그래밍 방식과 이터레이터 방식의 메모리 비교

### 메모리 확인을 위해 라이브러리 설치 필요

pip install memory-profiler

 

### 주피터 노트북 ver

## 라이브러리 불러오기

from memory_profiler import profile

### 주피터노트북에서는 아래 로드 처리 해야힘
%load_ext memory_profiler

 

## 이터레이터 클래스 생성하기

class SimpleIterator :
    def __init__(self, limit) :
        ### 반복 범위를 지정할 값(반복의 끝값)
        self.limit = limit
        ### 반복 시작값
        self.current = 0
        
    def __iter__(self) :
        return self

    def __next__(self) :
        if self.current < self.limit :
            self.current += 1
            return self.current
        else :
            raise StopIteration

 

## 데코레이터 함수 정의하기

### 이터레이터를 사용하지 않고 메모리 체크하기
@profile
def no_iterator(limit) :
    data = [i for i in range(1, limit+1)]

### 이터레이터를 사용해서 메모리 체크하기
@profile
def yes_iterator(limit) :
    data = SimpleIterator(limit)
    for item in data :
        ### 반복만 처리하고 별도 출력은 안함
        pass

 

## 데코레이터 함수 호출하기

limit = 1000000
try:
    %memit no_iterator(limit)

    %memit yes_iterator(limit)
except:
    pass
ERROR: Could not find file C:\Users\user\AppData\Local\Temp\ipykernel_3736\513312623.py
peak memory: 130.37 MiB, increment: 25.96 MiB
ERROR: Could not find file C:\Users\user\AppData\Local\Temp\ipykernel_3736\513312623.py
peak memory: 104.40 MiB, increment: 0.00 MiB

 

### 파이썬 ver

새로운 파일에 기존 주피터 노트북에 적은 코드에서 로드해오는 %load_ext memory_profiler 코드 빼고 작성하기

py 형태로 파일 저장한 뒤  프롬프트에서 실행하기

## 데코레이터 함수 호출하는 코드 수정

if __name__ == "__main__" :
    ### 데코레이터 함수 호출하기
    limit = 1000000

    print("no_iterator ------------------------\n")
    no_iterator(limit)
    
    print("yes_iterator ------------------------\n")
    yes_iterator(limit)

 

## 프롬프트에서 실행시 명령어

python -m memory_profiler 04_iterator_memory_test.py

 


간단실습

### 두개의 숫자(시작값, 종료값) 값을 이용해서, 짝수값만 반환하는 이터레이터 만들기

 

내가 만든 코드

class EvenNumberIterator :
    def __init__(self, start, end) :
        self.start = start
        self.end = end

    def __iter__(self) :
        return self

    def __next__(self) :
        if self.start <= self.end and self.start % 2 == 0  :
            self.start % 2 == 0
            result = self.start
            self.start += 2
            return result
        else :
            self.start += 1
            raise StopIteration

 

 

- 코드 실행

num_iterator = EvenNumberIterator(1, 20)
for v in num_iterator :
    print(v)
2
4
6
8
10
12
14
16
18
20

 

강사님 코드

class EvenNumberIterator :
    def __init__(self, start, end) :
        self.start = start
        self.end = end

    def __iter__(self) :
        return self

    def __next__(self) :
        # - 사용하는 값은 self.start 값만 사용
        for i in range(self.start, self.end, 1) :
            ### self.start가 짝수인지 체크
            if self.start % 2 == 0:
                ### 반환할 변수에 저장
                result = self.start
                # - self.start값은 1 증가
                self.start += 1
                # - 반환하기 : 반환하면 for문은 종료됨
                return result
            ### 짝수가 아니면
            else :
                # - 1증가만 시키고 반복을 계속 수행
                self.start += 1
                
        ### for문을 이용한 경우에는, 이터레이터 반복 종류 후 마지막에 아래 추가
        raise StopIteration

 

 

- 코드 실행

even_iter = EvenNumberIterator(1, 10)

for even in even_iter :
    print(even)
2
4
6
8

외부 함수를 이용해서 짝수값 추출하는 이터레이터 만들기

1. 이터레이터 클래스 생성하기

class EvenNumberIterator :
    ### 클래스 생성자 정의
    def __init__(self, start, end, func):
        # - 시작값
        self.start = start
        # - 종료값
        self.end = end
        # - 외부함수
        self.func = func

    ### 반복을 위한 이터레이터 함수 정의
    def __iter__(self):
        return self

    ### 반복 결과값을 처리할 함수 정의
    def __next__(self):
        ### 시작부터 종료까지 while 반복
        while self.start <= self.end :
            ### 외부함수로 짝수 or 홀수 체크
            # - 짝수면 True, 홀수면 False
            if self.func(self.start) :
                result = self.start
                self.start += 1
                return result
            else :
                self.start += 1
        ### 이터레이터 종료하기
        raise StopIteration

 

2. 짝수와 홀수를 판별하는 외부함수 정의하기

def is_even(num) :
    return num % 2 == 0

 

3. 이터레이터 클래스 생성하기

- 함수 이름을 그대로 변수로 넣으면 함수 자체를 실행

even_iter = EvenNumberIterator(1, 10, is_even)

### 이터레이터 반복 수행하기
for v in even_iter :
    print(v)

 텍스트 파일의 내용을 한줄씩 반환하는 이터레이터 만들기

1. 이터레이터 클래스 생성하기

- 파일명은 클래스가 받아서 처리

- readline() : 파일 정보중에 줄 하나 가지고 오는 함수

          >> 최초 이후부터는 다음 줄이 있는지 자동으로 체크 후 가지고 온다

          >> 다음 줄이 없으면 안가지고 온다.

class FileLineIterator :
    def __init__(self, file_path) :
    	# 파일 경로를 인스턴스 변수에 저장
        self.file_path = file_path
        # 파일 열기
        self.file = open(file_path, "r", encoding = "utf-8")
        
    def __iter__(self):
        return self
    
    def __next__(self):
        print("#1 ---------------------")
        
        # 파일에서 한 줄 읽어오기
        line = self.file.readline()
        
        # 읽어온 줄이 있으면 반환하고, 없으면 종료
        if line:
        	# strip은 문자열의 양 끝에서 공백 문자(공백, 탭, 개행문자 등)을 제거하는 역할
            return line.strip()
            
        else :
        	# 파일 닫기와 StopIteration 예외 발생
            print("#4 : 이터레이터 종료")
            self.file.close()
            raise StopIteration

 

 

2. 이터레이터 클래스 생성하기

file_path = "./04_example.txt"
file_iter = FileLineIterator(file_path)

 

3. 반복해서 파일 내용 한줄씩 출력하기

for line in file_iter :
    print(line)

 

- 메모장 내용과 주피터 노트북 실행 결과

# 결과
#1 ---------------------
가가가
#1 ---------------------
나나나
#1 ---------------------
다다다
#1 ---------------------
라라라
#1 ---------------------
#4 : 이터레이터 종료

 

 

 

728x90
반응형
728x90
반응형

<데코레이터(Decorator)>

- 대량 데이터 처리할때 사용

- wrapper는 한번 사용 하면 없어지므로 대용량 데이터에 대해 return으로 결과 값만 받아와서 사용
- 함수의 재사용성을 확장한 개념의 방법
- 자바의 오버라이드와 비슷한 개념


<함수 실행 시간 확인하는 데코레이터 프로그래밍 작성>

 

### 데코레이터 함수 정의하기
- func : 실제 처리할 함수 받아오는 매개 변수
- 외부에 있는 처리하고하 하는 함수가 func로 들어와야 함

- *args : 함수에 임의의 개수의 위치 인자를 전달할 때 사용한다. 함수 정의에서 *args는 튜플로 위치 인자들을 받는다. 이를 통해 함수는 몇 개의 위치 인자가 전달되든지 처리할 수 있다.

- **kwargs : 함수에 임의의 개수의 키워드 인자를 전달할 때 사용한다. 함수 정의에서 **kwargs는 딕셔너리로 키워드 인자들을 받는다. 이를 통해 함수는 몇 개의 키워드 인자가 전달되든지 처리할 수 있다.

def timer_decorator(func) :
    print(f"#1 : func = {func}")
    
    ### 실제 실행될 함수 정의(함수 이름은 자유롭게)
    # - func로 받은 함수를 아래 함수로 재정의하게 됨
    def wrapper(*args, **kwargs) :
        # - 시작시간
        start_time = time.time()
        print(f"#2 : start_time = {start_time}")

        ### 실제 처리할 함수 : func
        rs = func(*args, **kwargs)
        print(f"#3 : rs = {rs}")
        # - 종료시간
        end_time = time.time()
        print(f"#4 : end_time = {end_time}")
        return rs
    print("#5---------------")    
    return wrapper

 

### 데코레이터 호출 및 처리할 함수 정의하기

- 데코레이터 호출은 @로 사용함

- 데코레이터 함수 호출 시 및에 정의된 함수(exe_function)가 자동으로 전달 됨
- 매개변수 func은  메모리로 exe_function의 주소값을 이용
- 데코레이터 함수가 리턴한 wrapper함수는 exe_function이 된다. 즉, wrapper가 exe_function로 재정의 된다.
- 맨 처음 함수는 3개. 주소도 3개 그러나 재정의 할 경우 exe_function의 주소는 wrapper의 주소로 바뀜

# (재정의 되는 시점)
@timer_decorator 
def exe_function() : 
    print("실제 처리할 함수")
    ### 2초간 대기 : 데코레이터가 처리되는 시간을 벌어주기 위해서 
    time.sleep(2)
#1 : func = <function exe_function at 0x00000113C2EE1F80>
#5---------------

 

### 실제 처리하기

exe_function()
#2 : start_time = 1699930626.0731795
실제 처리할 함수
#3 : rs = None
#4 : end_time = 1699930628.0737495

<로그 데코레이터>

def log_decorator(func) :
    print(f"#1 : func = {func}")
    def wrapper(*args, **kwargs) :
        print(f"Logo : {func.__name__} 함수 호출됨")
        rs = func(*args, **kwargs)
        print(f"Logo : {func.__name__} 함수 종료됨")
        return rs
    print("#2-------------")
    return wrapper

 

### 데코레이터 호출 및 처리함수 정의

@log_decorator
def another_function():
    print("집에 가고싶다")
#1 : func = <function another_function at 0x00000113C3148B80>
#2-------------

 

### 처리함수 호출

another_function()
Logo : another_function 함수 호출됨
집에 가고싶다
Logo : another_function 함수 종료됨

<데코레이터 내부함수에서 처리된 결과를 받아보기>

# 함수 총 4개 사용
def check_permission(param_id) :
    print(f"#1: param_id = {param_id}")
    def decorator(func) :
        print(f"#2: func = {func}")
        def wrapper(*args, **kwargs) :
            check_id = "admin"
            print(f"#3: check_id = {check_id}")
            if check_id == param_id :
                args = ["인증성공"]
                print(f"#4: args = {args}")
                return func(*args, **kwargs)

            else :
                print(f"#5: raise 명령으로 강제 오류 발생시킴-----------")
                raise PermissionError("접근 불가")
        print(f"#6 -----------")
        return wrapper
    print(f"#7 -----------")
    return decorator

 

### 데코레이터 호출 및 처리함수 정의

@check_permission(param_id="admin")
def admin_function(re_msg) :
    print(f"인증 결과 : {re_msg}")
#1: param_id = admin
#7 -----------
#2: func = <function admin_function at 0x00000113C398B560>
#6 -----------

 

### 처리함수 호출

admin_function()
#3: check_id = admin
#4: args = ['인증성공']
인증 결과 : 인증성공

<영문 소문자 2개를 매개변수로 받아서, 대문자로 변환하는 데코레이터 프로그램>

- 함수이름 자유롭게 생성

- 데코레이터 함수 생성해서 대문자로 출력하기

 

작성해본 코드

def change_lang(func) :
    def lang_decorator(char1, char2) :
        char1_upper = char1.upper()
        char2_upper = char2.upper()
        result = func(char1_upper, char2_upper)

        return result
    return lang_decorator

@change_lang
def change_function(char1, char2) : 
    print(f"첫 번째 문자: {char1}")
    print(f"두 번째 문자: {char2}")

change_function('abcd', 'efgh')
첫 번째 문자: ABCD
두 번째 문자: EFGH

 

강사님 코드

def decorator_upper(func) :
    # args : 값 여러개 받음
    # kwargs : 리스트, 딕셔너리 받음
    ### 인자로 넘어온 2개의 소문자는 args 매개변수가 받게됨
    def wrapper(*args, **kwargs) :
        ### 인자로 넘겨받은 2개의 소문자를 대문자로 처리하는 영역
        args = [arg.upper() for arg in args]
        ### 대문자로 변환된 값 2개를 args에 리스트 타입으로 담아서 넘기면 됨
        return func(*args, **kwargs) 
    return wrapper

### 데코레이터 호출 및 처리 함수 정의
@decorator_upper
def getUpper(param1, param2) :
    print(f"대문자로 변환 : {param1} / {param2}")

### 처리하는 함수 호출 : 소문자 2개를 인자로 넘겨주기
getUpper("abcd", "efgh")
대문자로 변환 : ABCD / EFGH

 

데코레이터 실행 과정 이해하기

@decorator_upper가 실행 되면 getUpper함수가 같이 실행되면서

decorator_upper 주소 만들어지고 wrapper 주소 만들어짐
getUpper의 주소도 동시에 만들어졌지만 decorator_upper  호출되는 순간 getUpper 를 변수인 func에 넣게 됨
func는 getUpper의 주소를 갖는 변수가 된다
그때 return wrapper 하면 getUpper 가 바라보는 주소를 wrapper주소로  바꿔버림
wrapper 안에서 호출되는 func은  getUpper 의 주소를 받아서 갖고 있기 때문에 wrapper 에서 func의 원본인 getUpper 함수에 변수를 넣어 사용할 수 있는 것


<실습> 어제 작성한 도서관리 프로그램에 데코레이터를 적용하기

https://mzero.tistory.com/42

 

[Python] 파이썬 도서 관리 프로그램 만들기 실습 2

주제 : 도서 입고/대출/반납 관리를 위한 키오스크 파이썬 프로그램 실습 1. 주요내용 : 실습1에서 작성한 도서 관리 프로그램에 데코레이터를 적용하기 데코레이터 추가한 코드 ### 기능을 수행

mzero.tistory.com

 

728x90
반응형

+ Recent posts