광주인력개발원 일일포스팅(메모장)

13주차 목 1116 (이터레이터, 제너레이터, 정규표현식)

Jumbo96 2023. 11. 16. 16:53
728x90
반응형
<이터레이터(Iterator)>
파이썬에서 반복 가능한 객체(클래스)를 표현하는데 사용되는 인터페이스
이터레이터는 iter()함수와 next()함수를 이용하여 반복(Iterator)을 수행함
### 클래스 정의하기
class MyIterator :
    ### 클래스 생성자 정의하기
    def __init__(self) :
        self.cuurent_value = 0
        print(f"#1 (__init__) : self={self} / self.cuurent_value={self.cuurent_value}")
        
    ### 자신의 클래스를 반환하는 iter 함수 정의
    def __iter__(self) :
        print(f"#2 (__iter__) : self={self}")
        return self

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

            print(f"#4 : result={result} / self.cuurent_value={self.cuurent_value}")
            # - result 값 반환
            return result
        else :
            print("5 : StopIterator 예외 발생!!")
            ### 이터레이터는 반복이 끝나면 종류시켜야함
            # - 종료시키는 방법은 강제로 오류 발생시킴
            raise StopIteration
### 이터레이터 실행시키기
# - 클래스 생성하기
my_iterator = MyIterator()
#1 (__init__) : self=<__main__.MyIterator object at 0x00000170C96197D0> / self.cuurent_value=0
### 이터레이터 기능은 반복문 (for or while)을 사용해야만 작동하는 기능임
# - 최초 __iter__() 함수를 호출하고,
# - 출력 시 __next__() 함수가 한번씩 수행하면서 값을 반환받아서 출력함
# - 한번 반환된 후 메모리는 초기화 되며, 다음 반복시 다시 메모리를 사용
# ** 메모리를 효율적으로 활용할 수 있음

# 반복 수행하여 result 값 출력하기
for value in my_iterator :
    print(value)
#2 (__iter__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#4 : result=0 / self.cuurent_value=1
0
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#4 : result=1 / self.cuurent_value=2
1
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#4 : result=2 / self.cuurent_value=3
2
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#4 : result=3 / self.cuurent_value=4
3
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
#4 : result=4 / self.cuurent_value=5
4
#3 (__next__) : self=<__main__.MyIterator object at 0x00000170C96A9510>
5 : StopIterator 예외 발생!!
### 문자열 "Hello" 의 각 문자 하나씩 출력하는 프로그램을 작성해주세요.."hello"
for i in "Hello" :
    print(i)
H
e
l
l
o

 

내가 한 코드

### 이터레이터 클래스 생성해서 hello 각 단어 출력하기
# - 임의 문자열을 받아서 처리
# - 임의 문자열은 외부에서 클래스 생성시 넣어준다.
class StringIterator:
    def __init__(self) :
        self.wd = self.get_string()
        self.index = 0
    def __iter__(self) :
        return self
    def __next__(self) :
        if self.index < len(self.wd) :
            result = self.wd[self.index]
            self.index += 1
            return result
        else :
            raise StopIteration
            
    def get_string(self) :
        return input("문자열 : ")
iterator = StringIterator()
for char in iterator:
    print(char)
문자열 :  123456
1
2
3
4
5
6

 

강사님 코드

class StrintIterator :
    ### 클래스 생성자
    def __init__(self, p_text) :
        # - next함수에서 1씩 증가시키면서 반복 조건에 사용할 변수
        # - p_text는 지역변수
        # - text는 멤버변수
        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 = StrintIterator(msg)
### 반복문을 이용해서 전체 추출하기
for char in string_iter :
    print(char)
h
e
l
l
o

 

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

 

내가 한 코

class EvenNumberIterator:
    def __init__(self):
        self.current = 0
    def __iter__(self):
        return self
    def __next__(self) :
        if self.current < 10:
            if self.current % 2 == 0:
                result = self.current
                self.current += 1
                return result
            else:
                self.current += 1
                return self.__next__()
        else:
            raise StopIteration
num_iter = EvenNumberIterator()
for num in num_iter :
    print(num)
0
2
4
6
8

 

강사님 코드

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

        self.start = start
        self.end = end
    def __iter__(self) :
        return self
    def __next__(self) :
        ### start 부터 end 까지 무조건 반복 실행
        #- i 값은 사용 안함
        # - 사용하는 값은 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
<예제> 외부 함수를 이용해서 짝수값 추출하는 이터레이터 만들기>
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 :
            ### 외부함수로 짝수 of 홀수 체크
            # - 짝수면 True 홀수면 False
            if self.func(self.start) :
                result = self.start
                self.start += 1
                return result
            else :
                self.start += 1
            ### 이터레이터 종료하기
            raise StopIteration
### 짝수와 홀수를 판별하는 외부함수 정의하기
def is_even(num) :
    return num % 2 == 0
### 이터레이터 클래스 생성하기
even_iter = EvenNumberIterator(1, 10, is_even)

### 이터레이터 반복 수행하기
for even in even_iter :
    print(even)
<예제> 텍스트 파일의 내용을 한줄씩 반환하는 이터레이터 만들기

 

내가 한 코드

class FileLineIterator:
    def __init__(self, filename, encoding="utf-8"):
        self.filename = filename
        self.file = open(filename, 'r', encoding=encoding)

    def __iter__(self):
        return self

    def __next__(self):
        line = self.file.readline()
        if line:
            return line
        else:
            self.file.close()
            raise StopIteration

file_iter = FileLineIterator('./04_example.txt', encoding="utf-8")

for line in file_iter:
    print(line, end='')
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⢷⣷⣣⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⢏⣿⣿⡵⡀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣠⣮⣷⣿⣿⣿⣿⣷⣄⣄⠀⠀⠀⠀⠈⢞⣿⣿⡵⡀⠀⠀⠀⠀⠀
 ⠀⠀⡠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣏⢦⣤⡀⠀⠀⠀⠫⣻⣿⣾⢄⠀⠀⠀
 ⠀⣔⣿⣿⣿⣿⣿⣿⠿⣿⠻⢟⣿⣿⣿⣿⣿⡆⠀⠀⠀⠑⡿⣿⣯⢆⠀⠀
 ⢰⣸⢿⣻⢟⠃⠉⠉⠀⡠⠤⠸⣸⣿⣿⣿⡳⠁⠀⠀⠀⠀⡨⠺⠿⠇⢓⡄
 ⠧⠊⠁⠘⣖⣳⠠⣶⣋⡹⠁⠀⠛⣩⢻⠋⠀⠀⠀⠀⠀⢀⠇⠀⠀⠀⠀⢾⠀
⠀⠀⢠⠂⠁⠓⠒⠊⠀⡠⠤⡀⢠⠀⠚⠀⠀⠀⠀⠀⡠⠊⢀⠤⡤⣔⠩⠼⡀
⠀⠀⢇⠀⠀⢀⡠⢔⣪⠠⠖⠇⡘⠀⠀⠀⢀⠄⠒⠉⢀⠔⠁⠀⣧⢞⠮⠭⠵⡀
⠀⠀⠘⠒⠉⣾⣀⣀⠀⣀⣀⠦⠗⠹⠙⠃⠁⠀⡠⠔⡡⠔⠒⠉⡨⢴⢹⣿⣏⡆
⠀⠀⠀⠀⡸⠉⠀⠀⠁⠀⠀⠀⠀⣇⡠⡄⡶⠯⠔⠈⠀⠀⡠⠊⠀⠀⡿⣿⣿⡇
⠀⠀⠀⢀⠇⠀⠀⠀⠀⢀⣀⠤⡤⠵⠊⢸⠀⡠⠤⠤⠐⠉⠀⠀⠀⠀⣷⣿⢿⡇
⠀⠀⢀⠃⠀⢀⣀⣀⣀⣠⣀⣀⣿⠉⠉⠉⠉⠀⠀

 

강사님 코드

# - 파일명은 클래스가 받아서 처리
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 ---------------")
        ### readline() 파일 정보중에 줄 하나를 가지고온다.
        # - 최초 이후부터는 다음 줄이 있는지 자동으로 체크 후 가지고 온다.
        # - 다음 줄이 없으면 안 가져온다.
        line = self.file.readline()
        
        print(f"#2 : line = {line}")
        
        if line :
            print(f"#3 : line = {line}")
            return line.strip()
        else :
            print("#4 : 이터레이터 종료 ...")
            self.file.close()
            raise StopIteration

### 이터레이터 클래스 생성하기
file_path = "./04_example.txt"
file_iter = FileLineIterator(file_path)
### 반복해서 파일 내용 한줄씩 출력하기
for line in file_iter:
    print(line)
#1 ---------------
#2 : line =  이 기상과 이 맘으로 충성을 다하여

#3 : line =  이 기상과 이 맘으로 충성을 다하여

이 기상과 이 맘으로 충성을 다하여
#1 ---------------
#2 : line = 괴로우나 즐거우나 나라 사랑하세

#3 : line = 괴로우나 즐거우나 나라 사랑하세

괴로우나 즐거우나 나라 사랑하세
#1 ---------------
#2 : line = 무궁화 삼천리 화려 강산

#3 : line = 무궁화 삼천리 화려 강산

무궁화 삼천리 화려 강산
#1 ---------------
#2 : line = 대한 사람 대한으로 길이 보전하세
#3 : line = 대한 사람 대한으로 길이 보전하세
대한 사람 대한으로 길이 보전하세
#1 ---------------
#2 : line = 
#4 : 이터레이터 종료 ...

 

------------------------------------------------------------- 제너레이터 ----------------------------------------------------------------------------------

<제너레이터 (Generator)>
함수를 이용해서 이터레이터(반복)의 기능을 구현
이터레이터와 동일하게 호출 시점에만 메모리를 사용하고 사용이 끝나면 소멸됩니다.
반환할 때 사용하는 명령어는 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
<예제> 파일 한줄씩 일겅서 반환하는 제너레이터 만들기
### read_lines 함수 생성
def read_lines(file_path) :
    ### 파일처리 시 이터레이터와 다르게, with문을 사용해도 됩니다.
    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)
이 기상과 이 맘으로 충성을 다하여
괴로우나 즐거우나 나라 사랑하세
무궁화 삼천리 화려 강산
대한 사람 대한으로 길이 보전하세
 

------------------------------------------------------------- 정규표현식 ---------------------------------------------------------------------------------

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

* \d : 숫자 중 하나
* \b : 단어의 경계를 나타냄(보통 문장의 처음과 끝에 제시함)
--> 위의 패턴은 조합해서 사용 가능
"""

 

<예제> 특정 문자 추출하기

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

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

### text 문자열에서 패턴에 맞는 값만 추출하기
# - findall : 임의 문자열에서 패턴에 맞는 값을 모두 찾아서 리스트 타입으로 반환합니다.
rs_text = pattern.findall(text)
print(rs_text)
['a', 'd', 'e']

<예제> 점(.) 패턴을 이용하기

text = "abcdef afceeeeazc"
pattern = re.compile(r"a.c")
rs_text = pattern.findall(text)
print(rs_text)
['abc', 'afc', 'azc']

 

728x90
반응형
댓글수3