์ฝ๋ - ํจ์บ ์์ ์ฝ๋ ์ฐธ๊ณ (ํจ์บ ์์ ์ ๋ฆฌ)
<์ด์ ๊ธ>
https://silvercoding.tistory.com/30
[python ์ฌํ] 13. ์ฝ๋ฃจํด (coroutine) , yield from
์ฝ๋ - ํจ์บ ์์ ์ฝ๋ ์ฐธ๊ณ (ํจ์บ ์์ ์ ๋ฆฌ) <์ด์ ๊ธ> https://silvercoding.tistory.com/29 https://silvercoding.tistory.com/28 https://silvercoding.tistory.com/27 https://silvercoding.tistory.com/26..
silvercoding.tistory.com
* Future ๋์์ฑ / ๋น๋๊ธฐ ์์ ์คํ
: ์ง์ฐ์๊ฐ (Block) CPU ๋ฐ ๋ฆฌ์์ค ๋ญ๋น ๋ฐฉ์ง -> (FILE) Network I/O๊ด๋ จ ์์ ๋์์ฑ ํ์ฉ ๊ถ์ฅ
: ์ ํฉํ ์์ ์ผ ๊ฒฝ์ฐ ์์ฐจ ์งํ๋ณด๋ค ์๋์ ์ผ๋ก ์ฑ๋ฅ ํฅ์
* ์ด๋ฒ ํฌ์คํ ์์ ์ค์ตํ 3๊ฐ์ง
1. ์์ฐจ ์คํ
2. concurrent.futures ๋ฐฉ๋ฒ1
3. concurrent.futures ๋ฐฉ๋ฒ 2
import os
import time # ์ฑ๋ฅ์ธก์
import sys
import csv
# ๊ตญ๊ฐ ์ ๋ณด
NATION_LS = ('Singapore Germany Israel Norway Italy Canada France Spain Maxico').split()
# ์ด๊ธฐ CSV ์์น
TARGET_CSV = './resources/nations.csv'
# ์ ์ฅ ํด๋ ์์น
DEST_DIR = './csvs'
# CSV ํค๋ ๊ธฐ์ด ์ ๋ณด
HEADER = ['Region','Country','Item Type','Sales Channel','Order Priority','Order Date','Order ID','Ship Date','Units Sold','Unit Price','Unit Cost','Total Revenue','Total Cost','Total Profit']
<csv ํ์ผ : ํจ์คํธ ์บ ํผ์ค ์ ๊ณต>
NATION_LS : ์ฌ์ฉํ ๊ตญ๊ฐ ์ด๋ฆ ๋ฆฌ์คํธ
TARGET_CSV : csvํ์ผ์ด ์๋ ์์น ๊ฒฝ๋ก
DEST_DIR : ์ต์ข ์ ์ผ๋ก csvํ์ผ์ด ์ ์ฅ๋ ํด๋ ์์น ๊ฒฝ๋ก
HEADER : csv์ ํค๋๋ฅผ ์ถ์ถ ํด๋์ ๋ฆฌ์คํธ
- 1. ์์ฐจ์คํ ์์
ํฌ์คํ ์์๋ ์ฐจ๋ก๋๋ก ํจ์๋ฅผ ์์ฑํ์ง๋ง ๊ณต๋ถํ ๋๋ ๋ค์์๋ถํฐ( (6) ๋ถํฐ ) ๊ฑฐ์ฌ๋ฌ์ค๋ฉฐ ๊ณต๋ถํ๊ธฐ
(1) ๊ตญ๊ฐ๋ณ CSV ํ์ผ ์ ์ฅ
def save_csv(data, filename):
# ์ต์ข
๊ฒฝ๋ก ์์ฑ
path = os.path.join(DEST_DIR, filename)
with open(path, 'w', newline="") as fp:
writer = csv.DictWriter(fp, fieldnames=HEADER)
# Header Write
writer.writeheader()
# Dict to CSV write
for row in data:
writer.writerow(row)
์ต์ข csvํ์ผ์ ์ ์ฅํ๋ ํจ์์ด๋ค. ๊ตญ๊ฐ๋ณ๋ก ๋ง๋ค์ด์ง ๋ฐ์ดํฐ(data)์ ์์ฑํ ํ์ผ์ด๋ฆ(filename)์ ์ธ์๋ก ๋ฐ๋๋ค.
(2) ๊ตญ๊ฐ๋ณ ๋ถ๋ฆฌ
def get_sales_data(nt):
with open(TARGET_CSV, 'r') as f:
reader = csv.DictReader(f)
# Dict๋ฅผ ๋ฆฌ์คํธ๋ก ์ ์ฌ
data = []
# Header ํ์ธ
# print(reader.fieldnames)
for r in reader:
# OrderedDict ํ์ธ
# print(r)
# ์กฐ๊ฑด์ ๋ง๋ ๊ตญ๊ฐ๋ง ์ฝ์
if r['Country'] == nt:
data.append(r)
return data
๊ตญ๊ฐ์ ์ด๋ฆ(nt)์ ์ธ์๋ก ๋ฐ๋๋ค. csvํ์ผ์ ์ด์ด์ DictReader๋ก reader์ ๋ฐ์์ค๋ค. Country๊ฐ nt๊ตญ๊ฐ์ผ ๋ data๋ฆฌ์คํธ์ r์ ๋ฃ์ด์ค๋ค. ์ด๋ ๊ฒ ๊ตญ๊ฐ๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฆฌํด ์ฃผ๋ ํจ์์ด๋ค.
(3) ์ค๊ฐ ์ํฉ ์ถ๋ ฅ
def show(text):
print(text, end=' ')
# ์ค๊ฐ ์ถ๋ ฅ (๋ฒํผ ๋น์ฐ๊ธฐ)
sys.stdout.flush()
๊ตญ๊ฐ์ ์ด๋ฆ์ ๋ฐ์์ ํฐ๋ฏธ๋์ ์ถ๋ ฅํด ์ฃผ์ด ์งํ์ํฉ์ ์๋ ค์ฃผ๋ ํจ์์ด๋ค.
(4) ๊ตญ๊ฐ ๋ณ ๋ถ๋ฆฌ ํจ์ ์คํ - (1) , (2) , (3) ํจ์ ์ฌ์ฉ
def separate_many(nt_list):
for nt in sorted(nt_list):
# ๋ถ๋ฆฌ ๋ฐ์ดํฐ
data = get_sales_data(nt)
# ์ํฉ ์ถ๋ ฅ
show(nt)
# ํ์ผ ์ ์ฅ
save_csv(data, nt.lower() + '.csv')
return len(nt_list)
์ฌ๊ธฐ์ for๋ฌธ์ผ๋ก ๊ฐ ๊ตญ๊ฐ๋ณ ์ด๋ฆ์ ์์์ ๋ณด์๋ get_sales_data์ ๋ฃ์ด์ฃผ์ด ๋ถ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ csvํ์ผ๋ก ์ ์ฅํด์ฃผ๋ ํจ์๋ฅผ ๋ง๋ ๋ค. showํจ์๋ก ์งํ์ํฉ์ ์ถ๋ ฅํ๊ณ , save_csvํจ์๋ก ๊ฐ ๊ตญ๊ฐ๋ณ csvํ์ผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค.
(5) ์๊ฐ ์ธก์ ๋ฐ ๋ฉ์ธํจ์ - (4) ํจ์ ์ฌ์ฉ
def main(separate_many):
# ์์ ์๊ฐ
start_tm = time.time()
# ๊ฒฐ๊ณผ ๊ฑด์
result_cnt = separate_many(NATION_LS)
# ์ข
๋ฃ ์๊ฐ
end_tm = time.time() - start_tm
msg = '\n{} csv separated in {:.2f}s'
# ์ต์ข
๊ฒฐ๊ณผ ์ถ๋ ฅ
print(msg.format(result_cnt, end_tm))
๋๋์ด mainํจ์์์๋ separate_manyํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ตญ๊ฐ๋ณ csvํ์ผ์ ์์ฑํ๋๋ก ํ๊ณ , ์ด์ ๋ํ ์๊ฐ์ ์ธก์ ํ์ฌ ์ถ๋ ฅํด์ค๋ค.
(6) ์คํ - (5) ํจ์ ์ฌ์ฉ
if __name__ == '__main__':
main(separate_many)
Canada France Germany Israel Italy Maxico Norway Singapore Spain
9 csv separated in 21.09s
์ด๋ ๊ฒ mainํจ์๋ฅผ ์ฌ์ฉํด ์ฃผ๋ฉด ์์์ ๋ง๋ค์ด ๋์๋ ํจ์๋ค์ด ๋ชจ๋ ์คํ๋๋ฉฐ
๊ตญ๊ฐ๋ณ csv ํ์ผ์ด ๋ชจ๋ ๋ง๋ค์ด ์ง๋ค.
*** Google Python GIL (Global Interpreter Lock)
: GIL์ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง ์ํํ ์ ์๊ฒ ์ธํฐํ๋ฆฌํฐ ์์ฒด์์ ๋ฝ์ ๊ฑฐ๋ ๊ฒ์ด๋ค.
<python GIL ๊ด๋ จ๋ฌธ์>
https://wiki.python.org/moin/GlobalInterpreterLock
GlobalInterpreterLock - Python Wiki
In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of how t
wiki.python.org
- 2. concurrent.futures ๋ฐฉ๋ฒ1 (ThreadPoolExecutor, ProcessPoolExecutor)
<concurent.futures ์ฐธ๊ณ ๋ฌธ์>
https://docs.python.org/ko/3.7/library/concurrent.futures.html
concurrent.futures — ๋ณ๋ ฌ ์์ ์คํํ๊ธฐ — Python 3.7.11 ๋ฌธ์
์์ค ์ฝ๋: Lib/concurrent/futures/thread.py์ Lib/concurrent/futures/process.py concurrent.futures ๋ชจ๋์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฝ๋ฌ๋ธ์ ์คํํ๋ ๊ณ ์์ค ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋น๋๊ธฐ ์คํ์ (ThreadPoolExecutor๋ฅผ ์ฌ์ฉ
docs.python.org
: map() ์ฌ์ฉ
: ์๋ก ๋ค๋ฅธ ์ค๋ ๋ ๋๋ ํ๋ก์ธ์ค์์ ์คํ ๊ฐ๋ฅ
: ๋ด๋ถ ๊ณผ์ ์ ์ ํ์๊ฐ ์์ผ๋ฉฐ , ๊ณ ์์ค์ผ๋ก ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํจ .
...
from concurrent import futures
concurrent์ futres ๋ฅผ ์ถ๊ฐ๋ก import ํด์ค๋ค.
* (1) - (3) ์ ํจ์๋ ์๊ณผ ๋์ผํ๋ค.
(1) ๊ตญ๊ฐ๋ณ CSV ํ์ผ ์ ์ฅ
def save_csv(data, filename):
# ์ต์ข
๊ฒฝ๋ก ์์ฑ
path = os.path.join(DEST_DIR, filename)
with open(path, 'w', newline="") as fp:
writer = csv.DictWriter(fp, fieldnames=HEADER)
# Header Write
writer.writeheader()
# Dict to CSV write
for row in data:
writer.writerow(row)
(2) ๊ตญ๊ฐ๋ณ ๋ถ๋ฆฌ
def get_sales_data(nt):
with open(TARGET_CSV, 'r') as f:
reader = csv.DictReader(f)
# Dict๋ฅผ ๋ฆฌ์คํธ๋ก ์ ์ฌ
data = []
# Header ํ์ธ
# print(reader.fieldnames)
for r in reader:
# OrderedDict ํ์ธ
# print(r)
# ์กฐ๊ฑด์ ๋ง๋ ๊ตญ๊ฐ๋ง ์ฝ์
if r['Country'] == nt:
data.append(r)
return data
(3) ์ค๊ฐ ์ํฉ ์ถ๋ ฅ
def show(text):
print(text, end=' ')
# ์ค๊ฐ ์ถ๋ ฅ (๋ฒํผ ๋น์ฐ๊ธฐ)
sys.stdout.flush()
(4) ๊ตญ๊ฐ ๋ณ ๋ถ๋ฆฌ ํจ์ ์คํ - (1) , (2) , (3) ํจ์ ์ฌ์ฉ
def separate_many(nt):
# ๋ถ๋ฆฌ ๋ฐ์ดํฐ
data = get_sales_data(nt)
# ์ํฉ ์ถ๋ ฅ
show(nt)
# ํ์ผ ์ ์ฅ
save_csv(data, nt.lower() + '.csv')
return nt
1๋ฒ ๋ฐฉ๋ฒ์ธ ์์ฐจ์คํ์์๋ for๋ฌธ์ ์ด์ฉํ์ฌ ๊ตญ๊ฐ๋ณ csvํ์ผ์ ๋ง๋ค์ด๋๋ค. 2๋ฒ ๋ฐฉ๋ฒ์์๋ mapํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ตญ๊ฐ ์ด๋ฆ ๋ฆฌ์คํธ๋ฅผ ๋ฐ์ง ์๊ณ , ๊ตญ๊ฐ์ด๋ฆ ํ๋์ฉ์ ๋ฐ์ csvํ์ผ๋ก ์ ์ฅํ๋ค. ์ต์ข ์ ์ผ๋ก ๊ตญ๊ฐ์ด๋ฆ ํ๋(nt)๋ฅผ ๋ฆฌํดํ๋๋ก ๋ง๋ ๋ค.
(5) ์๊ฐ ์ธก์ ๋ฐ ๋ฉ์ธ ํจ์
futures.ThreadPoolExecutor() / futures.ProcessPoolExecutor
- ThreadPoolExecutor : GIL ์ข ์
def main(separate_many):
# worker ๊ฐ์
worker = min(20, len(NATION_LS))
# ์์ ์๊ฐ
start_tm = time.time()
# ๊ฒฐ๊ณผ ๊ฑด์
with futures.ThreadPoolExecutor(worker) as excutor:
# map -> ์์
์์ ์ ์ง, ์ฆ์ ์คํ
result = excutor.map(separate_many, sorted(NATION_LS))
# ์ข
๋ฃ ์๊ฐ
end_tm = time.time() - start_tm
msg = '\n{} csv separated in {:.2f}s'
# ์ต์ข
๊ฒฐ๊ณผ ์ถ๋ ฅ
print(msg.format(len(list(result)), end_tm))
# ์คํ
if __name__ == '__main__':
main(separate_many)
France Norway Spain Germany Maxico Canada Singapore Israel Italy
9 csv separated in 21.61s
worker ๋ผ๋ ์ผ๊พผ ๋ณ์๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ , ThreadPoolExecutor()์ ์ธ์์ ๋ฃ์ด์ค๋ค. ์ฌ๊ธฐ์ result๋ ์ ๋๋ ์ดํฐ ๊ฐ์ฒด๋ก ์ ์ฅ๋๋ค. ๋ฐ๋ผ์ ์ต์ข ๊ฒฐ๊ณผ ์ถ๋ ฅ์์ ๋ฆฌ์คํธ์ ๊ธธ์ด๋ฅผ ์๊ธฐ ์ํด result๋ฅผ list ํ์ ์ผ๋ก ๋ฐ๊ฟ์ฃผ์ด์ผ ํ๋ค.
๋ง์ฝ ๊ทธ๋ฅ len(result)๋ก ์์ฑํ๋ค๋ฉด !
File "c:/Users/./Desktop/python_high/chapter06_03_02.py", line 100, in main
result_cnt = len(excutor.map(separate_many, sorted(NATION_LS)))
TypeError: object of type 'generator' has no len()
์ ๋๋ ์ดํฐ๋ len() ๋ฅผ ๊ฐ์ง ์๋๋ค๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.
- ProcessPoolExecutor : GIL ์ฐํ, ๋ณ๊ฒฝ ํ -> ๋ด๋ถ์ ์ผ๋ก os.cpu_count() ๋ฉ์๋ ํธ์ถ (์ด์์ฒด์ ์์ฒด์์ ์ฐํ์์ ๊ฐ -> ์๋๊ฐ ๋น ๋ฆ )
def main(separate_many):
# worker ๊ฐ์
worker = min(20, len(NATION_LS))
# ์์ ์๊ฐ
start_tm = time.time()
# ๊ฒฐ๊ณผ ๊ฑด์
with futures.ProcessPoolExecutor() as excutor:
# map -> ์์
์์ ์ ์ง, ์ฆ์ ์คํ
result = excutor.map(separate_many, sorted(NATION_LS))
# ์ข
๋ฃ ์๊ฐ
end_tm = time.time() - start_tm
msg = '\n{} csv separated in {:.2f}s'
# ์ต์ข
๊ฒฐ๊ณผ ์ถ๋ ฅ
print(msg.format(len(list(result)), end_tm))
# ์คํ
if __name__ == '__main__':
main(separate_many)
Norway Canada Germany France Spain Singapore Italy Maxico Israel
9 csv separated in 8.11s
๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ProcessPoolExecutor๋ฅผ ํด๋ณธ๋ค. ์๊ฐ์ด ํจ์ฌ ๋จ์ถ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ธ์ ProcessPoolExecutor์ฐ๊ณ , ThreadPoolExecutor์ฐ๊ณ , ์ฝ๋ฃจํด์ ์ฐ๋์ง๋ฅผ ์๊ฐํด์ผ ํ๋ค. ProcessPoolExecutor์ฐ๋ฉด cpu ์ฌ์ฉ๋์ด ๊ธ๊ฒฉํ ์ฆ๊ฐํ๊ณ ๋น ๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค. ๊ทธ๋์ ์ด๋ฌํ ๋ฉํฐ ํ๋ก์ธ์ฑ์ ๋จ๊ธฐ๊ฐ์ ๋ฅ๋ฌ๋ ๊ณ ์ ์ฐ์ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. ThreadPoolExecutor์ฌ์ฉํ๋ฉด ์๋๋ ๋ ๊ฑธ๋ฆฌ์ง๋ง cpu ์ฌ์ฉ๋์ ์์ํ๊ฒ ์ฆ๊ฐํ๋ค. ์ด ๋๊ฐ์ง์ ์ฐจ์ด๋ฅผ ๊ตฌ๋ถํ๊ณ , ์ ์ ํ ์ฌ์ฉํด์ผ ํ๋ค.
- 3. concurrent.futures ๋ฐฉ๋ฒ2 (map()ํจ์ ๋์ for๋ฌธ์ ์ด์ฉํ์ฌ ์ธ๋ถ์ ์ธ ๊ณผ์ ์ฐ์ด๋ณด๊ธฐ)
* (1) - (3) ์ ํจ์๋ ์๊ณผ ๋์ผํ๋ค.
(4) ๊ตญ๊ฐ ๋ณ ๋ถ๋ฆฌ ํจ์ ์คํ - (1) , (2) , (3) ํจ์ ์ฌ์ฉ
def main(separate_many):
# worker ๊ฐ์
worker = min(20, len(NATION_LS))
# ์์ ์๊ฐ
start_tm = time.time()
# futures
futures_list = []
# ๊ฒฐ๊ณผ ๊ฑด์
# ProcessPoolExecutor : GIL ์ฐํ, ๋ณ๊ฒฝ ํ -> ๋ด๋ถ์ ์ผ๋ก os.cpu_count() ๋ฉ์๋ ํธ์ถ (์ด์์ฒด์ ์์ฒด์์ ์ฐํ์์ ๊ฐ)
# ThreadPoolExecutor : GIL ์ข
์
# with futures.ThreadPoolExecutor(worker) as excutor:
with futures.ProcessPoolExecutor() as excutor:
# submit -> callable ๊ฐ์ฒด ์ค์ผ์ฅด๋ง(์คํ ์์ฝ) -> future
# Future -> as_complete(), result(), done(), cancelled() ์ฃผ๋ก ์ฌ์ฉ
for nt in sorted(NATION_LS):
# future ๋ฐํ
future = excutor.submit(separate_many, nt)
# ์ค์ผ์ฅด๋ง
futures_list.append(future)
# ์ถ๋ ฅ
# print('Scheduled for {} : {}'.format(nt, future))
# print()
for future in futures.as_completed(futures_list):
result = future.result()
done = future.done()
cancelled = future.cancelled()
# furue ๊ฒฐ๊ณผ ํ์ธ
print('Future Result : {}, Done : {}'.format(result, done))
print('Future Cancelled : {}'.format(cancelled))
# ์ข
๋ฃ ์๊ฐ
end_tm = time.time() - start_tm
msg = '\n{} csv separated in {:.2f}s'
# ์ต์ข
๊ฒฐ๊ณผ ์ถ๋ ฅ
print(msg.format(len(futures_list), end_tm))
for๋ฌธ์ผ๋ก ์์ ์ ์ผ์ผ์ด ํ๊ณ , ์ธ๋ถ์ ์ผ๋ก ์งํ์ํฉ๊ณผ ์ด๋ป๊ฒ ๋ง๋ฌด๋ฆฌ ๋์๋์ง๋ฅผ ์๊ณ ์ถ์ ๋ ์ด ๋ฐฉ๋ฒ์ ์ด๋ค.
2๋ฒ ๋ฐฉ๋ฒ์์๋ map()ํจ์๋ฅผ ์ด์ฉํ์ฌ separate_many ํจ์๋ก ๊ตญ๊ฐ๋ณ csvํ์ผ์ ์ ์ฅํด ์ฃผ์๋ค. 3๋ฒ ๋ฐฉ๋ฒ์์๋ submit()ํจ์๋ฅผ ์ด์ฉํ์ฌ futre๋ณ์์ ํ ๋นํด์ฃผ๊ณ , ์ด future๋ฅผ futures_list์ append ํด์ค๋ค.
futures.as_complted()์ ์ธ์์ futures_list๋ฅผ ๋ฃ์ด์ฃผ๊ณ , ๊ฐ๊ฐ์ future์ ๋ํ result, done, cancelled ๊ฐ์ ์ป์ ์ ์๋ค.
* ์คํ
if __name__ == '__main__':
main(separate_many)
Germany Canada Future Result : Germany, Done : True
Future Cancelled : False
Norway Israel Future Result : Norway, Done : True
Italy Future Cancelled : False
Future Result : Canada, Done : True
Future Cancelled : False
Future Result : Israel, Done : True
Future Cancelled : False
Future Result : Italy, Done : True
Future Cancelled : False
Singapore France Future Result : Singapore, Done : True
Future Cancelled : False
Future Result : France, Done : True
Future Cancelled : False
Maxico Future Result : Maxico, Done : True
Future Cancelled : False
Spain Future Result : Spain, Done : True
Future Cancelled : False
9 csv separated in 8.60s
์คํ์ ํด๋ณด๋ฉด , result๋ ๊ฐ ๊ตญ๊ฐ์ ์ด๋ฆ(nt : separate_many์ ๋ฆฌํด๊ฐ), Done์ ๋ชจ๋ True, Cancelled๋ ๋ชจ๋ False๊ฐ ๋์ ์ ์์ ์ผ๋ก ์๋ํ ๊ฒ์ ๋ณผ ์ ์๋ค. ์ด์ ๊ฐ์ด for๋ฌธ๊ณผ submitํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋ถ์ ์ธ ๋ด์ฉ์ ํ์ธํ ์๋ ์๋ค.
'ํ๋ก๊ทธ๋๋ฐ ์ธ์ด > Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[python ๊ธฐ์ด] 1. print ํจ์ (0) | 2021.07.30 |
---|---|
[python ์ฌํ] 15. Asyncio, async await (0) | 2021.07.24 |
[python ์ฌํ] 13. ์ฝ๋ฃจํด (coroutine) , yield from (0) | 2021.07.19 |
[python ์ฌํ] 12. ๋ด๋ถ iter ํจ์, ์ ๋๋ ์ดํฐ(Generator) (0) | 2021.07.17 |
[python ์ฌํ] 11. ํด๋์ค Getter, Setter, ์ถ์ํด๋์ค , class ABC (0) | 2021.07.14 |