Better way 65 try/except/else/finally์ ๊ฐ ๋ธ๋ก์ ์ ํ์ฉํ๋ผ
๋ธ๋ก | ์ฉ๋ |
try | ์์ธ๊ฐ ๋ฐ์ํ ์ ์๋ ์ต์ํ์ ์ฝ๋๋ง ํฌํจ |
except | ์์ธ ์ฒ๋ฆฌ |
else | ์์ธ ์์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ์ ์ฒ๋ฆฌ (except์ผ๋ก ๋น ์ง ๊ฒฝ์ฐ ์คํ X) |
finally | ์์ธ ์ฌ๋ถ์ ๋ฌด๊ดํ๊ฒ ๋ฐ๋์ ์คํ๋์ด์ผ ํ๋ ๋ถ๋ถ (ํ์ผ ๋ซ๋ ๋ฑ) |
์ ์ข์ ์์ - try๋ฌธ ์์ ์์ธ ๋ฐ์ ์ฝ๋ & ์ํ๋ ์ฝ๋๊ฐ ์์ฌ ์์
import threading
lock = threading.Lock()
def critical_section_basic():
lock.acquire()
try:
result = 10 / 0 # โ ์์ธ ๋ฐ์ ๊ฐ๋ฅ
print("โ
์์
์ฑ๊ณต:", result)
except ZeroDivisionError:
print("โ 0์ผ๋ก ๋๋ ์ ์์ต๋๋ค.")
finally:
lock.release()
print("๐ Lock ํด์ ์๋ฃ")
critical_section_basic()
๊ฐ์ - else๋ฅผ ํ์ฉํ์ฌ ์์ธ ๋ฐ์ ๊ฐ๋ฅ ์ฝ๋๋ง try์ ๋ฐฐ์นํ์ฌ ๊ฐ๋ ์ฑ ํฅ์
import threading
lock = threading.Lock()
def critical_section_better():
lock.acquire()
try:
result = 10 / 2 # โ ์์ธ ๋ฐ์ ๊ฐ๋ฅ
except ZeroDivisionError:
print("โ 0์ผ๋ก ๋๋ ์ ์์ต๋๋ค.")
else:
print("โ
์์
์ฑ๊ณต:", result) # ์์ธ๊ฐ ์์ ๋๋ง ์คํ
finally:
lock.release()
print("๐ Lock ํด์ ์๋ฃ")
critical_section_better()
Better way 66 ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ try/finally ๋์์ ์ํ๋ค๋ฉด contextlib๊ณผ with ๋ฌธ์ ์ฌ์ฉํ๋ผ
@contextmanager
- ์ปจํ ์คํธ ๋งค๋์ ์์ฑ๊ธฐ
- yield
- with ๋ธ๋ก์ ๊ฐ์ฒด๋ฅผ ์ ๋ฌ
- finally
- with ๋ธ๋ก์ด ๋๋๋ฉด ํญ์ ์คํ๋จ
์์ ํ์ผ ์ด๊ณ , ์ข ๋ฃ ์ ์๋ ์ ๋ฆฌํ๋ ์ปจํ ์คํธ ๋งค๋์ ์์ฑ๊ธฐ
from contextlib import contextmanager
@contextmanager
def managed_file(path):
print("๐ ํ์ผ ์ด๊ธฐ")
f = open(path, 'w')
try:
yield f # ํ์ผ์ with ๋ธ๋ก ์์ผ๋ก ๋๊น
finally:
print("โ ํ์ผ ๋ซ๊ธฐ")
f.close()
# with ๋ธ๋ก์ผ๋ก ์ฌ์ฉ
with managed_file("sample.txt") as f:
f.write("Hello, contextlib!")
Better way 67 ์ง์ญ ์๊ฐ์๋ time๋ณด๋ค๋ datetime์ ์ฌ์ฉํ๋ผ
ํญ๋ชฉ | time ๋ชจ๋ | datetime ๋ชจ๋ |
ํ์์กด ์ง์ | OS ์์กด (๋ถ์์ ) | ๋ช ์์ ์ค์ ๊ฐ๋ฅ (์ผ๊ด๋จ) |
์๊ฐ ๊ณ์ฐ | ์ง์ timestamp ๊ณ์ฐ ํ์ | timedelta๋ก ์ง๊ด์ ๊ณ์ฐ ๊ฐ๋ฅ |
ํ๋ซํผ ํธํ์ฑ | Windows/Linux ๊ฒฐ๊ณผ ๋ค๋ฅผ ์ ์์ | ํ๋ซํผ ๋ ๋ฆฝ์ |
์ถ์ฒ ์ฉ๋ | ํ์ด๋จธ, ๋ฒค์น๋งํฌ ๋ฑ ์์คํ ์๊ฐ | ๋ก๊น , ์ฌ์ฉ์ ์๊ฐ ํ์, ์๊ฐ๋ ์ฒ๋ฆฌ ๋ฑ |
time ๋ชจ๋์ C ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ time.h๋ฅผ ๋ํํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด์์ฒด์ ์ ๋ฐ๋ผ ์๊ฐ/ํ์์กด ์ค์ ์ด ์ ๋๋ก ๋์ํ์ง ์์ ์ ์๋ค.
๊ทธ๋ ๊ธฐ์ datetime ๋ชจ๋์ ์ฌ์ฉํ์
import time
import os
# ํ๊ฒฝ๋ณ์๋ก ํ์์กด์ ์์๋ก ๋ฐ๊ฟ (Linux/macOS์์๋ง ๋์)
os.environ['TZ'] = 'Asia/Seoul'
time.tzset() # ํ๊ฒฝ์ ๋ฐ๋ผ ์ด ํจ์ ์์ฒด๊ฐ ์์ (Windows ๋ฏธ์ง์)
print("๐ time.localtime():", time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
# ํ์์กด์ UTC๋ก ๋ณ๊ฒฝ
os.environ['TZ'] = 'UTC'
time.tzset()
print("๐ time.localtime() in UTC:", time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
์์ ์ฝ๋๋ Windows ์์๋ ์ ์์ ์ผ๋ก ๋์ํ์ง ์๋๋ค.
from datetime import datetime, timezone, timedelta
# ๋ช
์์ ์ผ๋ก UTC ๊ธฐ์ค
utc_now = datetime.now(timezone.utc)
print("๐ UTC ์๊ฐ:", utc_now.strftime('%Y-%m-%d %H:%M:%S %Z'))
# ํ๊ตญ ์๊ฐ (UTC+9)
kst = timezone(timedelta(hours=9))
local_now = utc_now.astimezone(kst)
print("๐ฐ๐ท KST ์๊ฐ:", local_now.strftime('%Y-%m-%d %H:%M:%S %Z'))
datetime์ ํ๋ซํผ ๋ ๋ฆฝ์ ์ด๊ธฐ์ OS์ ์๊ด์์ด ์๋ํ๋ค.
Better way 69 ์ ํ๋๊ฐ ๋งค์ฐ ์ค์ํ ๊ฒฝ์ฐ์๋ decimal์ ์ฌ์ฉํ๋ผ
์ธ๊ธ, ์๊ธ ๋ฑ์ ์์ซ์ ๋จ์์ ์ ํํ ๊ฐ์ด ์ค์ํ ๊ฒฝ์ฐ decimal์ ์ฌ์ฉํ์.
ํตํ๋ฃ๋ฅผ ๊ณ์ฐํด๋ณด์
- ํตํ๋ฃ
- 1.45 ๋ฌ๋ฌ/๋ถ
- ์๊ฐ
- 3๋ถ 42์ด
rate = 1.45
seconds = 3*60 + 42
cost = rate * seconds / 60
print(cost) # ์ค์ ๊ฐ์ 5.365
>>> 5.364999999999999
์ค์ ๊ฐ ๋ณด๋ค 0.0.0000000000000001 ๋ณด๋ค ์๋ค.
from decimal import Decimal
rate = Decimal('1.45') # Decimal(1.45)์ ๊ฒฐ๊ณผ๊ฐ ๋ค๋ฅด๋ค
seconds = Decimal(3*60 + 42)
cost = rate * seconds / Decimal(60)
print(cost) # ์ค์ ๊ฐ์ 5.365
>>> 5.365
์ ํํ ๊ฐ์ด ๊ณ์ฐ๋๋ค.
Better way 70 ์ต์ ํํ๊ธฐ ์ ์ ํ๋กํ์ผ๋ง์ ํ๋ผ
ํญ๋ชฉ | cProfile | profile |
๊ตฌํ ๋ฐฉ์ | C๋ก ๊ตฌํ๋ ํ๋กํ์ผ๋ฌ | ์์ ํ์ด์ฌ์ผ๋ก ๊ตฌํ๋ ํ๋กํ์ผ๋ฌ |
์ฑ๋ฅ ์ค๋ฒํค๋ | ๋งค์ฐ ์ ์ (๊ณ ์) | ๋๋ฆผ (ํด์ ๋จ๊ณ์์ ๋๋ฆผ) |
์ ํ๋ | ์ ํํ๊ณ ์ค์ ์คํ ํ๊ฒฝ ๋ฐ์ ์๋จ | ์ ํํ์ง๋ง ๋๋ ค์ ์ธก์ ๋์์ ์ํฅ ์ค ์ ์์ |
์ถ์ฒ ์ฉ๋ | ์ผ๋ฐ์ ์ธ ์ฑ๋ฅ ๋ถ์, ์ค์ ์ฝ๋์ ์ ํฉ | ๊ต์ก, ๋ถ์ ๋ชฉ์ , ๋๋ฒ๊น ์ ๋์ ์ ํฉ |
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ | import cProfile | import profile |
profile์ ๊ฒฝ์ฐ ์์ ํ์ด์ฌ์ด๊ธฐ์ ์ธก์ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ด cProfile์ ์ฌ์ฉํ์
import cProfile
def slow_sum():
total = 0
for i in range(1000000):
total += i
return total
def fast_sum():
return sum(range(1000000))
def run():
slow_sum()
fast_sum()
cProfile.run('run()')
์ถ๋ ฅ ๊ฒฐ๊ณผ
6 function calls in 0.135 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.102 0.102 0.123 0.123 profile_demo.py:4(slow_sum)
1 0.000 0.000 0.011 0.011 profile_demo.py:10(fast_sum)
1 0.000 0.000 0.135 0.135 profile_demo.py:13(run)
1 0.000 0.000 0.135 0.135 {built-in method builtins.exec}
1 0.000 0.000 0.135 0.135 <string>:1(<module>)
์ปฌ๋ผ ์ด๋ฆ | ์ค๋ช |
ncalls | ํธ์ถ ํ์ |
tottime | ํด๋น ํจ์ ์์ฒด์์ ์ฌ์ฉํ ์๊ฐ (ํ์ ํจ์ ์ ์ธ) |
percall | ํธ์ถ๋น ํ๊ท ์๊ฐ (tottime / ncalls) |
cumtime | ํด๋น ํจ์ ํฌํจ ์ ์ฒด ์คํ ์๊ฐ (ํ์ ํจ์ ํฌํจ) |
filename:lineno(function) | ํจ์ ์์น |
Better way 71 ์์ฐ์-์๋น์ ํ๋ก deque๋ฅผ ์ฌ์ฉํ๋ผ
์ฐ์ฐ | list ์๊ฐ ๋ณต์ก๋ | deque ์๊ฐ ๋ณต์ก๋ |
append(x) | O(1) | O(1) |
pop() | O(1) | O(1) |
pop(0) | โ O(n) (์ ์์๋ค ์ด๋) | โ O(1) |
popleft() | โ ์์ | โ O(1) |
import time
from collections import deque
N = 100000
# list ์ฌ์ฉ
lst = list(range(N))
start = time.time()
while lst:
lst.pop(0) # โ O(n) ์ฐ์ฐ
end = time.time()
print(f"list pop(0) ์ฒ๋ฆฌ ์๊ฐ: {end - start:.4f}์ด")
# deque ์ฌ์ฉ
dq = deque(range(N))
start = time.time()
while dq:
dq.popleft() # โ
O(1) ์ฐ์ฐ
end = time.time()
print(f"deque popleft() ์ฒ๋ฆฌ ์๊ฐ: {end - start:.4f}์ด")
list pop(0) ์ฒ๋ฆฌ ์๊ฐ: 5.4321์ด
deque popleft() ์ฒ๋ฆฌ ์๊ฐ: 0.0043์ด
๋ฆฌ์คํธ๋ ๋์ ๋ฐฐ์ด(array) ๊ตฌ์กฐ๋ก ๊ตฌํ๋ผ ์์
pop(0)์ ํ๋ฉด
- ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์ ๊ฑฐํ ํ,
- ๋จ์ ๋ชจ๋ ์์๋ค์ ์์ผ๋ก ํ ์นธ์ฉ ๋ฐ์ด์ผ ํจ โ O(n) ์๊ฐ
์ด ์์ ์ด ๋ง์์ง๋ฉด ์ฑ๋ฅ์ด ์ ํ์ ์ผ๋ก ๋๋ ค์ง
Better way 72 ์ ๋ ฌ๋ ์ํ์ค๋ฅผ ๊ฒ์ํ ๋๋ bisect๋ฅผ ์ฌ์ฉํ๋ผ
bisect ์ฃผ์ ํจ์
ํจ์ | ์ค๋ช |
bisect.bisect_left(a, x) | x๋ฅผ ๋ฃ์ ์ ์๋ ๊ฐ์ฅ ์ผ์ชฝ ์ธ๋ฑ์ค ๋ฐํ |
bisect.bisect_right(a, x) | x๋ฅผ ๋ฃ์ ์ ์๋ ๊ฐ์ฅ ์ค๋ฅธ์ชฝ ์ธ๋ฑ์ค ๋ฐํ |
bisect.insort(a, x) | ์ ๋ ฌ๋ ๋ฆฌ์คํธ a์ x๋ฅผ ์ฝ์ (์ ๋ ฌ ์ ์ง) |
import time
import bisect
import random
N = 1000000
sorted_list = list(range(N)) # 0 ~ 999,999 ๊น์ง ์ ๋ ฌ๋ ๋ฆฌ์คํธ
target = random.randint(0, N)
# ์ ํ ํ์
start = time.time()
for i, x in enumerate(sorted_list):
if x >= target:
linear_result = i
break
linear_time = time.time() - start
print(f"๐ ์ ํ ํ์ ์์น: {linear_result}, ์๊ฐ: {linear_time:.6f}์ด")
# bisect ์ด์ง ํ์
start = time.time()
bisect_result = bisect.bisect_left(sorted_list, target)
bisect_time = time.time() - start
print(f"โก bisect ํ์ ์์น: {bisect_result}, ์๊ฐ: {bisect_time:.6f}์ด")
๐ ์ ํ ํ์ ์์น: 725394, ์๊ฐ: 0.261245์ด
โก bisect ํ์ ์์น: 725394, ์๊ฐ: 0.000015์ด
- ์ ๋ ฌ๋ ๋ฆฌ์คํธ์์๋ for ๋ฃจํ ๋์ bisect ์ฌ์ฉ
- bisect๋ ์ด์ง ํ์ ๊ธฐ๋ฐ -> O(log n)
- ๋ฆฌ์คํธ๊ฐ ํด์๋ก ์ฑ๋ฅ ์ฐจ์ด๋ ์๋์
Better way 73 ์ฐ์ ์์ ํ๋ก heapq๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๋๋ผ
import time
import heapq
import random
N = 10000
data = [random.randint(1, 100000) for _ in range(N)]
# ๋ฆฌ์คํธ + sort ๋ฐฉ์
lst = []
start = time.time()
for num in data:
lst.append(num)
lst.sort() # โ ๋งค๋ฒ ์ ์ฒด ์ ๋ ฌ
_ = lst[0] # ์ต์๊ฐ ์กฐํ
end = time.time()
print(f"๐ list + sort() ๋ฐฉ์: {end - start:.4f}์ด")
# heapq ๋ฐฉ์
heap = []
start = time.time()
for num in data:
heapq.heappush(heap, num) # โ
์ ๋ ฌ ์์ด push
_ = heap[0] # ์ต์๊ฐ ์กฐํ๋ ํญ์ heap[0]
end = time.time()
print(f"โก heapq ๋ฐฉ์: {end - start:.4f}์ด")
๐ list + sort() ๋ฐฉ์: 1.3826์ด
โก heapq ๋ฐฉ์: 0.0194์ด
- ์ฐ์ ์์๊ฐ ์๋ ์์ ์ฒ๋ฆฌ์๋ ๋ฆฌ์คํธ + sort ๋์ heapq๋ฅผ ์ฐ์
- ์ฝ์ ๊ณผ ์ต์๊ฐ ์กฐํ๊ฐ O(log n) ๋๋ **O(1)**๋ก ๋น ๋ฅด๋ค
- ๋ฐ๋ณต ์ฝ์ /์กฐํ๊ฐ ๋ง์ ๊ฒฝ์ฐ ์ฑ๋ฅ์ด ์์ญ ๋ฐฐ ์ด์ ๋นจ๋ผ์ง๋ค
'๐ Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ดํํฐ๋ธ ํ์ด์ฌ 7์ฅ - ๋์์ฑ๊ณผ ๋ณ๋ ฌ์ฑ (0) | 2025.04.01 |
---|---|
์ดํํฐ๋ธ ํ์ด์ฌ 6์ฅ - ๋ฉํํด๋์ค์ ์ ํธ๋ฆฌ๋ทฐํธ (0) | 2025.03.30 |
์ดํํฐ๋ธ ํ์ด์ฌ 5์ฅ - ํด๋์ค์ ์ธํฐํ์ด์ค (0) | 2025.03.21 |
์ดํํฐ๋ธ ํ์ด์ฌ 3์ฅ - ํจ์ (0) | 2025.03.17 |
์ดํํฐ๋ธ ํ์ด์ฌ 2์ฅ - ๋ฆฌ์คํธ์ ๋์ ๋๋ฆฌ (0) | 2025.03.12 |