[AI Assignment - Python] ๐ ์ ๋๋ ์ดํฐ ์ค์ โ batch, file reader, infinite ID
๐ฏ ๊ณผ์ ๊ฐ์
๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์์ ์์ฃผ ์ฐ์ด๋ ์ ๋๋ ์ดํฐ 3๊ฐ๋ฅผ ๊ตฌํํด๋ดค์ต๋๋ค.
batch_generatorโ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์น ๋จ์๋ก ๋๋๊ธฐfile_line_readerโ ๋์ฉ๋ ํ์ผ์ ํ ์ค์ฉ ์ฝ๊ธฐ (๋น ์ค ์ฒ๋ฆฌ ์ต์ )infinite_id_generatorโ ๋ฌดํ ๊ณ ์ ID ์์ฑ๊ธฐ
์๊ตฌ์ฌํญ: ๋ชจ๋ ํจ์์ ํ์
ํํธ, Generator ๋๋ Iterator ์ฌ์ฉ, ํ์ผ์ด ์์ผ๋ฉด FileNotFoundError ๋ฐ์, next()์ for ๋ ๋ฐฉ์ ๋ชจ๋ ํ
์คํธ.
๐ ์ ๋๋ ์ดํฐ ๊ธฐ๋ณธ ๊ฐ๋
์ ๋๋ ์ดํฐ๋ ๊ฐ์ ํ ๋ฒ์ ๋ค ๋ง๋ค์ง ์๊ณ , ํ์ํ ๋ ํ๋์ฉ ๋ง๋ค์ด๋ด๋ ํจ์์
๋๋ค. return ๋์ yield๋ฅผ ์ฌ์ฉํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
# ์ผ๋ฐ ํจ์ โ ๋ฆฌ์คํธ๋ฅผ ํต์งธ๋ก ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆผ
def get_numbers(n: int) -> list[int]:
result = []
for i in range(n):
result.append(i ** 2)
return result # 1์ต ๊ฐ๋ฉด ๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ
# ์ ๋๋ ์ดํฐ โ ํ๋์ฉ ์์ฑ
def gen_numbers(n: int):
for i in range(n):
yield i ** 2 # 1์ต ๊ฐ์ฌ๋ ๋ฉ๋ชจ๋ฆฌ 1๊ฐ๋ถ๋ง ์ฌ์ฉ
1๏ธโฃ batch_generator
1์ฐจ ์๋
1
2
3
4
5
def batch_generator(data: list, batch_size: int):
for i in range(len(data)):
if i * batch_size >= len(data):
return
yield data[i * batch_size:i * batch_size + batch_size]
๋์์ ๋ง์ง๋ง range(len(data))๋ฅผ ๋ง๋ค์ด๋๊ณ ๋๋ถ๋ถ ๋ฒ๋ฆฝ๋๋ค. 10๊ฐ ๋ฐ์ดํฐ๋ฉด range(10)์ด์ง๋ง ์ค์ ๋ก ํ์ํ ๊ฑด 4๋ฒ ๋ฃจํ๋ฟ์
๋๋ค.
โ
๊ฐ์ : range์ step ์ธ์ ํ์ฉ
range(start, stop, step)์ ์ธ ๋ฒ์งธ ์ธ์๋ก ์ฆ๊ฐํญ์ ์ง์ ํ ์ ์์ต๋๋ค.
1
2
3
def batch_generator(data: list, batch_size: int) -> Iterator[list]:
for i in range(0, len(data), batch_size): # 0, 3, 6, 9
yield data[i:i + batch_size]
์ฌ๋ผ์ด์ฑ์ด ๋ฒ์๋ฅผ ์ด๊ณผํด๋ ์๋ฌ ์์ด ์๋ผ์ฃผ๊ธฐ ๋๋ฌธ์(data[9:12] โ [9]), ์กฐ๊ฑด๋ฌธ๋ return๋ ํ์ํ์ง ์์ต๋๋ค.
2๏ธโฃ file_line_reader
์ฌ๋ฌ ๋ฒ ํค๋งธ๋ ํจ์์ ๋๋ค. ์๋๋ณ๋ก ์ ๋ฆฌํฉ๋๋ค.
1์ฐจ ์๋ โ ๋ ๊ฐ์ง ๋ฌธ์
1
2
3
4
5
6
7
def file_line_reader(filepath: str, skip_empty: bool = True):
try:
with open(filepath, 'r', encoding='utf-8') as file:
for line in file:
yield line.strip()
except FileNotFoundError:
print("ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค. ๊ฒฝ๋ก๋ฅผ ํ์ธํด์ฃผ์ธ์.")
โ skip_empty๋ฅผ ๊ตฌํํ์ง ์์. ํ๋ผ๋ฏธํฐ๋ ๋ฐ์๋๊ณ ์ ํ ์ฌ์ฉํ์ง ์์ ๋น ์ค์ด ๊ทธ๋๋ก ์ถ๋ ฅ๋ฉ๋๋ค.
โก ์๋ฌ๋ฅผ print๋ก ๋ฎ์ด๋ฒ๋ฆผ. ์๊ตฌ์ฌํญ์ โFileNotFoundError๋ฅผ ๋ฐ์์ํจ๋คโ์๋๋ฐ, try/except๋ก ์ก์์ ์กฐ์ฉํ ์ฒ๋ฆฌํ๊ณ ์์์ต๋๋ค.
1
2
3
4
5
# ํธ์ถ์ ์
์ฅ์์
for line in file_line_reader("์๋ํ์ผ.csv"):
process(line)
# โ "ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค" ์ถ๋ ฅ ํ for ๋ฃจํ 0ํ ์คํ
# โ ๋ฒ๊ทธ๊ฐ ์กฐ์ฉํ ์จ์ด๋ฒ๋ฆผ
โ ๏ธ ์๋ฌ๋ฅผ
2์ฐจ ์๋ โ skip_empty ์๋ฏธ๋ฅผ ์๋ชป ์ดํด
1
2
3
4
5
6
7
8
9
10
def file_line_reader(filepath: str, skip_empty: bool = True):
if os.path.exists(filepath):
with open(filepath, 'r', encoding='utf-8') as file:
for line in file:
if skip_empty:
yield line.strip()
else:
yield line
else:
print(f"'{filepath}' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.")
os.path.exists๋ก ๋จผ์ ์ฒดํฌํ๋๋ก ๋ฐ๊ฟจ์ง๋ง ์ฌ์ ํ ์์ ๋ print๋ง ํ๊ณ ์กฐ์ฉํ ๋๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ skip_empty์ ์๋ฏธ๋ฅผ ์์ ํ ์๋ชป ์ดํดํ์ต๋๋ค.
| ๋ด๊ฐ ๊ตฌํํ ์๋ฏธ | ์ค์ ์๋ฏธ |
|---|---|
True โ strip() ์ ์ฉ | True โ ๋น ์ค ๊ฑด๋๋ฐ๊ธฐ |
False โ strip() ๋ฏธ์ ์ฉ | False โ ๋น ์ค๋ yield |
strip()์ skip_empty์ ๋ฌด๊ดํ๊ฒ ํญ์ ์ ์ฉ๋์ด์ผ ํฉ๋๋ค. skip_empty๋ strip ์ดํ ๋น ๋ฌธ์์ด์ด๋ฉด ๊ฑด๋๋ธ์ง ๊ฒฐ์ ํ๋ ํ๋๊ทธ์
๋๋ค.
โ 3์ฐจ ์๋ (์์ฑ) โ EAFP ํจํด
1
2
3
4
5
6
7
def file_line_reader(filepath: str, skip_empty: bool = True) -> Iterator[str]:
with open(filepath, 'r', encoding='utf-8') as file:
for line in file:
stripped = line.strip()
if skip_empty and not stripped: # ๋น ๋ฌธ์์ด์ falsy
continue
yield stripped
EAFP ํจํด ์ ์ฉ. os.path.exists๋ก ๋จผ์ ์ฒดํฌ(LBYL)ํ์ง ์๊ณ , open()์ด ์์์ FileNotFoundError๋ฅผ ๋์ง๋๋ก ๋ก๋๋ค. ์ด๊ฒ์ด ํ์ด์ฌ ์ฒ ํ์ธ EAFP(Easier to Ask for Forgiveness than Permission) ์
๋๋ค.
skip_empty ์ฌ๋ฐ๋ฅธ ๊ตฌํ. strip()์ ํญ์ ์ ์ฉํ๊ณ , ๋น ๋ฌธ์์ด์ด๋ฉด continue๋ก ๊ฑด๋๋๋๋ค. Python์์ ๋น ๋ฌธ์์ด์ falsy์ด๋ฏ๋ก not stripped๋ก ์ฒดํฌํ ์ ์์ต๋๋ค.
Tip: LBYL(โ๋๋์ง ํ์ธํ๊ณ ํด๋ผโ)๋ณด๋ค EAFP(โ์ผ๋จ ํด๋ณด๊ณ ์ ๋๋ฉด ์์ธโ)๊ฐ ๋ ํ์ด์ฌ๋ค์ด ๋ฐฉ์์ ๋๋ค.
3๏ธโฃ infinite_id_generator
1
2
3
4
5
def infinite_id_generator(prefix: str = "item") -> Iterator[str]:
count = 0
while True:
count += 1
yield f"{prefix}_{count:04d}"
while True + yield๋ก ๋ฌดํ ์์ฑํฉ๋๋ค. f"{count:04d}"๋ 4์๋ฆฌ 0ํจ๋ฉ์
๋๋ค. ์ ๋๋ ์ดํฐ๋ next() ํธ์ถ ์ฌ์ด์ ์ํ๋ฅผ ์ ์งํ๋ฏ๋ก count๊ฐ ์๋์ผ๋ก ๋์ ๋ฉ๋๋ค.
โถ๏ธ ์คํ ๊ฒฐ๊ณผ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
=== batch_generator ===
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]
=== file_line_reader(skip_empty=True) ===
'์์ธ,15.2,45,32.1'
'๋ถ์ฐ,17.8,61,22.3'
'๋๊ตฌ,19.3,38,41.5'
'์ธ์ฒ,14.7,55,29.8'
=== file_line_reader(skip_empty=False) ===
'์์ธ,15.2,45,32.1'
'๋ถ์ฐ,17.8,61,22.3'
''
'๋๊ตฌ,19.3,38,41.5'
''
'์ธ์ฒ,14.7,55,29.8'
=== ์๋ ํ์ผ ===
FileNotFoundError: [Errno 2] No such file or directory: 'nonexistent.csv'
=== infinite_id_generator ===
user_0001
user_0002
user_0003
๐ท๏ธ ํ์
ํํธ โ Generator vs Iterator
Generator์ ํ์
ํ๋ผ๋ฏธํฐ๋ 3๊ฐ์
๋๋ค.
1
Generator[YieldType, SendType, ReturnType]
- YieldType โ
yield๋ก ๋ด๋ณด๋ด๋ ๊ฐ์ ํ์ - SendType โ
.send()๋ก ์ ๋๋ ์ดํฐ์ ๊ฐ์ ๋ณด๋ผ ๋์ ํ์ - ReturnType โ ์ ๋๋ ์ดํฐ๊ฐ ๋๋ ๋
returnํ๋ ๊ฐ์ ํ์
๋๋ถ๋ถ์ YieldType๋ง ์ ๊ฒฝ์ฐ๋ฉด ๋๋ฏ๋ก ๋๋จธ์ง๋ None์ผ๋ก ๋๊ฒ ๋ฉ๋๋ค. ๋ ๊ฐ๊ฒฐํ ๋ฐฉ๋ฒ์ Iterator๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
1
2
3
4
from collections.abc import Iterator
def batch_generator(data: list, batch_size: int) -> Iterator[list]:
...
Tip:
.send()๋ return ๊ฐ์ ์ฌ์ฉํ ์ผ์ด ์๋ค๋ฉดGenerator[T, None, None]๋์Iterator[T]๊ฐ ํจ์ฌ ๊น๋ํฉ๋๋ค.
๐ก ์ด๋ฒ ๊ณผ์ ์์ ๋ฐฐ์ด ๊ฒ
yield์ ๊ธฐ๋ณธ ๋์: ํจ์๊ฐ yield๋ฅผ ๋ง๋๋ฉด ๊ฐ์ ๋ด๋ณด๋ด๊ณ ์ผ์์ ์งํฉ๋๋ค. ๋ค์ ํธ์ถ์์ ๊ทธ ์๋ฆฌ๋ถํฐ ์ฌ๊ฐํฉ๋๋ค.
range(start, stop, step): ์ฆ๊ฐํญ์ ์ง์ ์ง์ ํ ์ ์์ต๋๋ค. range(0, len(data), batch_size) ๊ฐ์ ํจํด์ ํ์ด์ฌ ์ด๋์๋ ํ์ฉ๋ฉ๋๋ค.
EAFP ํจํด: os.path.exists๋ก ๋จผ์ ์ฒดํฌ(LBYL)ํ๋ ๋์ , ์ผ๋จ open()์ ์๋ํ๊ณ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ์ฒ๋ฆฌ(EAFP)ํ๋ ๊ฒ์ด ๋ ํ์ด์ฌ๋ต์ต๋๋ค.
์๋ฌ๋ฅผ ์จ๊ธฐ์ง ๋ง๊ธฐ: try/except๋ก ์ก์์ print๋ก ๋ฎ๋ ๊ฒ์ ๋๋ฒ๊น
์ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค. ํธ์ถ์๊ฐ ์์ธ๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌํ ์ ์๋๋ก ์์ฐ์ค๋ฝ๊ฒ ๋ฐ์์์ผ์ผ ํฉ๋๋ค.
skip_empty ๊ฐ์ ํ๋ผ๋ฏธํฐ์ ์๋ฏธ: ์ด๋ฆ๋ง ๋ณด๊ณ ์ถ์ธกํ์ง ๋ง๊ณ ์๊ตฌ์ฌํญ์ ์ ํํ ์ฝ์ด์ผ ํฉ๋๋ค.
ํ์
ํํธ ๊ฐ๊ฒฐํ๊ฒ: Generator[T, None, None] ๋์ Iterator[T]๋ฅผ ์ฌ์ฉํฉ์๋ค.
๐ ๋ฐ๋ณตํด์ ๋ํ๋ ํจํด
์ธ ๊ณผ์ ๋ฅผ ์งํํ๋ฉด์ ๋ฐ๋ณต์ ์ผ๋ก ๋ง์ฃผ์น ๋ ๊ฐ์ง ํจํด์ด ์์ต๋๋ค.
โ ํ๋์ฝ๋ฉ ์์กด: result == 'done', isinstance(arg, int), skip_empty ์คํด โ ์ ๋ถ ํน์ ๊ฐ์ด๋ ์ํฉ์ ์์กดํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ ์ต๊ด์
๋๋ค. ๋ฒ์ฉ ํจ์๋ฅผ ๋ง๋ค ๋๋ ์๋์ ์ผ๋ก ์ถ์ํํด์ผ ํฉ๋๋ค.
โก ์๋ฌ ์จ๊น: ์๋ฌ๋ฅผ ๊ฐ์ผ๋ก ๋ฐํํ๊ฑฐ๋ print ํ ์กฐ์ฉํ ์ข
๋ฃํ๋ฉด ํธ์ถ์๋ ๋ฌด์์ด ์๋ชป๋๋์ง ์ ์ ์์ต๋๋ค. ์์ธ๋ ์ ์ ํ ๋ ์ด์ด์์ ์ฒ๋ฆฌ๋์ด์ผ ํฉ๋๋ค.