cross-cutting-concern
decorator with oop
import logging
# Abstract Base Class (interfaceX->추상클래스를 인터페이스 처럼 활용!)
from abc import ABC, abstractmethod
from math import sqrt
from time import perf_counter
def is_prime(number: int) -> bool:
if number < 2:
return False
for element in range(2, int(sqrt(number)) + 1):
if number % element == 0:
return False
return True
# abstract class AbstractComponent
class AbstractComponent(ABC):
#1
@abstractmethod
def execute(self, upper_bound: int) -> int:
pass
# class ConcreteComponent extends abstract class AbstractComponent
class ConcreteComponent(AbstractComponent):
def execute(self, upper_bound: int) -> int:
count = 0
for number in range(upper_bound):
if is_prime(number):
count += 1
return count
# 2
# abstract class AbstractDecorator extends abstract class AbstractComponent->추상 클래스가 추상 클래스를 상속(자바에서도 가능한 문법!)
class AbstractDecorator(AbstractComponent):
def __init__(self, decorated: AbstractComponent) -> None:
self._decorated = decorated
# 3
# class BenchmarkDecorator extends abstract class AbstractDecorator
class BenchmarkDecorator(AbstractDecorator):
def execute(self, upper_bound: int) -> int:
start_time = perf_counter()
value = self._decorated.execute(upper_bound)
end_time = perf_counter()
run_time = end_time - start_time
logging.info(
f"Execution of {self._decorated.__class__.__name__} took {run_time:.2f} seconds."
)
return value
# 4
# class LoggingDecorator extends abstract class AbstractDecorator
class LoggingDecorator(AbstractDecorator):
def execute(self, upper_bound: int) -> int:
logging.info(f"Calling {self._decorated.__class__.__name__}")
value = self._decorated.execute(upper_bound)
logging.info(f"Finished {self._decorated.__class__.__name__}")
return value
def main() -> None:
logging.basicConfig(level=logging.INFO)
component = ConcreteComponent()
# 5
benchmark_decorator = BenchmarkDecorator(component)
logging_decorator = LoggingDecorator(benchmark_decorator)
logging_decorator.execute(50000)
if __name__ == "__main__":
main()
ConcreteComponent.execute를 통해 구현하고 있다.
INFO:root:Calling BenchmarkDecorator
INFO:root:Execution of ConcreteComponent took 0.03 seconds.
INFO:root:Finished BenchmarkDecorator
decorator with wrapper
import logging
from math import sqrt
from time import perf_counter
from typing import Any, Callable
# 1
# func can get Any type parameter,cause we did not decide the func(관심사항(func함수)을 수행하는데 아직 func가 정해지지 않았으므로 Any으로 명시!)
def with_logging(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any) -> Any:
logging.info(f"Calling {func.__name__}")
value = func(*args, **kwargs)
logging.info(f"Finished {func.__name__}")
return value
return wrapper
# 2
def benchmark(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any) -> Any:
start_time = perf_counter()
value = func(*args, **kwargs)
end_time = perf_counter()
run_time = end_time - start_time
logging.info(f"Execution of {func.__name__} took {run_time:.2f} seconds.")
return value
return wrapper
def is_prime(number: int) -> bool:
if number < 2:
return False
for element in range(2, int(sqrt(number)) + 1):
if number % element == 0:
return False
return True
# 3
def count_prime_numbers(upper_bound: int) -> int:
count = 0
for number in range(upper_bound):
if is_prime(number):
count += 1
return count
# 4
def main() -> None:
logging.basicConfig(level=logging.INFO)
# 4
benchmark_wrapper = benchmark(count_prime_numbers)
logging_wrapper = with_logging(benchmark_wrapper)
logging_wrapper(50000)
count_prime_numbers(50000)
if __name__ == "__main__":
main()
INFO:root:Calling wrapper
INFO:root:Execution of count_prime_numbers took 0.03 seconds.
INFO:root:Finished wrapper
decorator
import logging
from math import sqrt
from time import perf_counter
from typing import Any, Callable
def with_logging(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any) -> Any:
logging.info(f"Calling {func.__name__}")
value = func(*args, **kwargs)
logging.info(f"Finished {func.__name__}")
return value
return wrapper
def benchmark(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any) -> Any:
start_time = perf_counter()
value = func(*args, **kwargs)
end_time = perf_counter()
run_time = end_time - start_time
logging.info(f"Execution of {func.__name__} took {run_time:.2f} seconds.")
return value
return wrapper
def is_prime(number: int) -> bool:
if number < 2:
return False
for element in range(2, int(sqrt(number)) + 1):
if number % element == 0:
return False
return True
# 1
# benchmark_wrapper = benchmark(count_prime_numbers)
# logging_wrapper = with_logging(benchmark_wrapper)
@with_logging
@benchmark
def count_prime_numbers(upper_bound: int) -> int:
count = 0
for number in range(upper_bound):
if is_prime(number):
count += 1
return count
def main() -> None:
logging.basicConfig(level=logging.INFO)
count_prime_numbers(50000)
if __name__ == "__main__":
main()
INFO:root:Calling wrapper
INFO:root:Execution of count_prime_numbers took 0.03 seconds.
INFO:root:Finished wrapper
decorator with functools
import logging
from math import sqrt
from time import perf_counter
from typing import Any, Callable
import functools
# 1
logger = logging.getLogger("my_app")
def with_logging(
func: Callable[..., Any], logger: logging.Logger
) -> Callable[..., Any]:
# 2
@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
logger.info(f"Calling {func.__name__}")
value = func(*args, **kwargs)
logger.info(f"Finished {func.__name__}")
return value
return wrapper
def benchmark(func: Callable[..., Any]) -> Callable[..., Any]:
@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
start_time = perf_counter()
value = func(*args, **kwargs)
end_time = perf_counter()
run_time = end_time - start_time
logging.info(f"Execution of {func.__name__} took {run_time:.2f} seconds.")
return value
return wrapper
def is_prime(number: int) -> bool:
if number < 2:
return False
for element in range(2, int(sqrt(number)) + 1):
if number % element == 0:
return False
return True
# 3
with_default_logging = functools.partial(with_logging, logger=logger)
# 4
@with_default_logging
@benchmark
def count_prime_numbers(upper_bound: int) -> int:
count = 0
for number in range(upper_bound):
if is_prime(number):
count += 1
return count
def main() -> None:
logging.basicConfig(level=logging.INFO)
count_prime_numbers(50000)
if __name__ == "__main__":
main()
INFO:my_app:Calling count_prime_numbers
INFO:root:Execution of count_prime_numbers took 0.04 seconds.
INFO:my_app:Finished count_prime_numbers