파이썬, 유용한 다섯 가지 데코레이터
00:32 @retry <-- 재시도에 관해서는 Tenacity 라이브러리를 살펴보는 것도 좋다.
02:52 @cache <-- 캐시 데코레이터의 가장 좋은 용도 중 하나는 재귀 함수이다. 모든 재귀 호출은 캐시된다.
05:50 @get_time
07:51 @deprecated
10:58 @on_exit
소스 코드 깃허브 : https://github.com/indently/five_decorators
https://www.youtube.com/watch?v=3_P-dxrNCq8
[소스 코드] 001_retry.py
import time
from functools import wraps
from typing import Callable, Any
from time import sleep
def retry(retries: int = 3, delay: float = 1) -> Callable:
"""
Attempt to call a function, if it fails, try again with a specified delay.
:param retries: The max amount of retries you want for the function call
:param delay: The delay (in seconds) between each function retry
:return:
"""
# Don't let the user use this decorator if they are high
if retries < 1 or delay <= 0:
raise ValueError('Are you high, mate?')
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs) -> Any:
for i in range(1, retries + 1): # 1 to retries + 1 since upper bound is exclusive
try:
print(f'Running ({i}): {func.__name__}()')
return func(*args, **kwargs)
except Exception as e:
# Break out of the loop if the max amount of retries is exceeded
if i == retries:
print(f'Error: {repr(e)}.')
print(f'"{func.__name__}()" failed after {retries} retries.')
break
else:
print(f'Error: {repr(e)} -> Retrying...')
sleep(delay) # Add a delay before running the next iteration
return wrapper
return decorator
@retry(retries=3, delay=1)
def connect() -> None:
time.sleep(1)
raise Exception('Could not connect to internet...')
def main() -> None:
connect()
if __name__ == '__main__':
main()
[소스 코드] 002_caching.py
import time
from functools import cache
@cache
def count_vowels(text: str) -> int:
"""
A function that counts all the vowels in a given string.
:param text: The string to analyse
:return: The amount of vowels as an integer
"""
vowel_count: int = 0
# Pretend it's an expensive operation
print(f'Bot: Counting vowels in: "{text}"...')
time.sleep(2)
# Count those damn vowels
for letter in text:
if letter in 'aeiouAEIOU':
vowel_count += 1
return vowel_count
def main() -> None:
while True:
user_input: str = input('You: ')
if user_input == '!info':
print(f'Bot: {count_vowels.cache_info()}')
elif user_input == '!clear':
print('Bot: Cache cleared!')
count_vowels.cache_clear()
else:
print(f'Bot: "{user_input}" contains {count_vowels(user_input)} vowels.')
if __name__ == '__main__':
main()
[소스 코드] 003_timing.py
import time
from time import perf_counter, sleep
from functools import wraps
from typing import Callable, Any
def get_time(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs) -> Any:
# Note that timing your code once isn't the most reliable option
# for timing your code. Look into the timeit module for more accurate
# timing.
start_time: float = perf_counter()
result: Any = func(*args, **kwargs)
end_time: float = perf_counter()
print(f'"{func.__name__}()" took {end_time - start_time:.3f} seconds to execute')
return result
return wrapper
# Sample function 1
@get_time
def connect() -> None:
print('Connecting...')
sleep(2)
print('Connected!')
# Sample function 2
@get_time
def fifty_million_loops() -> None:
fifty_million: int = int(5e7)
print('Looping...')
for _ in range(fifty_million):
pass
print('Done looping!')
def main() -> None:
fifty_million_loops()
connect()
if __name__ == '__main__':
main()
[소스 코드] 004_deprecated.py
# XXX
# XXX TALK ABOUT PEP 702
# XXX https://peps.python.org/pep-0702
# XXX
from deprecated import deprecated
@deprecated("Adding ain't cool no more", version="1.0.0")
def add(x: int, y: int) -> int:
return x + y
if __name__ == "__main__":
print(add(5, 7))
[소스 코드] 005_on_exit_1.py
import atexit
@atexit.register
def exit_handler() -> None:
print("We're exiting now!")
def main() -> None:
for i in range(10):
print(2**i)
if __name__ == "__main__":
main()
atexit.unregister(exit_handler)
1 / 0
[소스 코드] 005_on_exit_2.py
import atexit
import sqlite3
cxn = sqlite3.connect("db.sqlite3")
def init_db():
cxn.execute("CREATE TABLE IF NOT EXISTS memes (id INTEGER PRIMARY KEY, meme TEXT)")
print("Database initialised!")
@atexit.register
def exit_handler():
cxn.commit()
cxn.close()
print("Closed database!")
if __name__ == "__main__":
init_db()
1 / 0
...
반응형
'Python 기초' 카테고리의 다른 글
클로저, 람다를 이용한 validator 파이썬 예제 (0) | 2025.01.29 |
---|---|
파이썬, 랜덤 값 다양한 기능 예제 (0) | 2025.01.26 |
파이썬, f 문자열 기초와 활용 예제 (0) | 2025.01.18 |
파이썬, 비밀번호가 문자/숫자/특수문자 조합이고 8자리 이상 검증 (0) | 2025.01.06 |
파이썬, 디버깅 print는 ic를 이용하면 좋아요. (0) | 2024.12.20 |