From ee7428ca44f041b7c828282b9e802e0b9dd29a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleyna=20G=C3=BCltekin?= Date: Thu, 22 Oct 2026 20:32:34 +0300 Subject: [PATCH 1/5] Add custom power and equation functions with counter Defines a custom power function and an equation function that combines two terms raised to specified powers. Also implements a counter function to track calls from different callers. --- Week04/functions_aleyna_gultekin.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Week04/functions_aleyna_gultekin.py diff --git a/Week04/functions_aleyna_gultekin.py b/Week04/functions_aleyna_gultekin.py new file mode 100644 index 00000000..c0d1e909 --- /dev/null +++ b/Week04/functions_aleyna_gultekin.py @@ -0,0 +1,44 @@ +import sys + +custom_power = lambda x=0, /, e=1: x ** e + + +def custom_equation(x: int = 0, y: int = 0, /, a: int = 1, b: int = 1, *, c: int = 1) -> float: + """ + Raises x to the power a and y to the power b, adds them and divides by c. + + :param x: Base of the first term (positional-only) + :type x: int + :param y: Base of the second term (positional-only) + :type y: int + :param a: Power applied to x + :type a: int + :param b: Power applied to y + :type b: int + :param c: Number to divide the sum by (keyword-only) + :type c: int + :return: The calculated value + :rtype: float + """ + first_term = x ** a + second_term = y ** b + return float((first_term + second_term) / c) + + +def _make_counter(): + calls = {"count": 0} + by_caller = {} + + def fn_w_counter() -> tuple[int, dict[str, int]]: + name = sys._getframe(1).f_globals.get("__name__") + calls["count"] += 1 + if name in by_caller: + by_caller[name] += 1 + else: + by_caller[name] = 1 + return calls["count"], by_caller + + return fn_w_counter + + +fn_w_counter = _make_counter() From 5f77f8c9b71c297af698e6dca05540c4a82eff41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleyna=20G=C3=BCltekin?= Date: Thu, 22 Oct 2026 20:37:29 +0300 Subject: [PATCH 2/5] Refactor fn_w_counter return type and remove sys import --- Week04/functions_aleyna_gultekin.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Week04/functions_aleyna_gultekin.py b/Week04/functions_aleyna_gultekin.py index c0d1e909..450d895f 100644 --- a/Week04/functions_aleyna_gultekin.py +++ b/Week04/functions_aleyna_gultekin.py @@ -1,5 +1,3 @@ -import sys - custom_power = lambda x=0, /, e=1: x ** e @@ -29,8 +27,8 @@ def _make_counter(): calls = {"count": 0} by_caller = {} - def fn_w_counter() -> tuple[int, dict[str, int]]: - name = sys._getframe(1).f_globals.get("__name__") + def fn_w_counter() -> (int, dict[str, int]): + name = fn_w_counter.__module__ calls["count"] += 1 if name in by_caller: by_caller[name] += 1 From a4814488501ff7f2d63e992e0e89a98a997347db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleyna=20G=C3=BCltekin?= Date: Thu, 22 Oct 2026 20:44:38 +0300 Subject: [PATCH 3/5] Add performance decorator for function statistics Introduced a performance decorator to collect function execution statistics including time and memory usage. --- Week04/decorators_aleyna_gultekin.py | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Week04/decorators_aleyna_gultekin.py diff --git a/Week04/decorators_aleyna_gultekin.py b/Week04/decorators_aleyna_gultekin.py new file mode 100644 index 00000000..32bff065 --- /dev/null +++ b/Week04/decorators_aleyna_gultekin.py @@ -0,0 +1,31 @@ +import time +import tracemalloc +import functools + + +class performance: + """Decorator class collecting performance statistics of functions.""" + counter = 0 + total_time = 0.0 + total_mem = 0 + + def __init__(self, func): + functools.update_wrapper(self, func) + self.func = func + + def __call__(self, *args, **kwargs): + was_tracing = tracemalloc.is_tracing() + if not was_tracing: + tracemalloc.start() + mem_before = tracemalloc.get_traced_memory()[0] + t0 = time.perf_counter() + try: + return self.func(*args, **kwargs) + finally: + t1 = time.perf_counter() + mem_after, peak = tracemalloc.get_traced_memory() + if not was_tracing: + tracemalloc.stop() + performance.counter += 1 + performance.total_time += t1 - t0 + performance.total_mem += max(peak - mem_before, 0) From 48749cec94bcccba7c4aa435e64f684d68240fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleyna=20G=C3=BCltekin?= Date: Thu, 5 Nov 2026 14:53:31 +0300 Subject: [PATCH 4/5] Refactor fn_w_counter to improve call tracking Refactor counter function to track calls and callers. --- Week04/functions_aleyna_gultekin.py | 32 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Week04/functions_aleyna_gultekin.py b/Week04/functions_aleyna_gultekin.py index 450d895f..dbd1894e 100644 --- a/Week04/functions_aleyna_gultekin.py +++ b/Week04/functions_aleyna_gultekin.py @@ -23,20 +23,26 @@ def custom_equation(x: int = 0, y: int = 0, /, a: int = 1, b: int = 1, *, c: int return float((first_term + second_term) / c) -def _make_counter(): - calls = {"count": 0} - by_caller = {} +def fn_w_counter() -> tuple[int, dict[str, int]]: + if not hasattr(fn_w_counter, "call_count"): + fn_w_counter.call_count = 0 + fn_w_counter.callers = {} - def fn_w_counter() -> (int, dict[str, int]): - name = fn_w_counter.__module__ - calls["count"] += 1 - if name in by_caller: - by_caller[name] += 1 - else: - by_caller[name] = 1 - return calls["count"], by_caller + try: + raise Exception + except Exception as error: + caller = error.__traceback__.tb_frame.f_back.f_globals["__name__"] - return fn_w_counter + fn_w_counter.call_count += 1 + if caller in fn_w_counter.callers: + fn_w_counter.callers[caller] += 1 + else: + fn_w_counter.callers[caller] = 1 + return fn_w_counter.call_count, fn_w_counter.callers -fn_w_counter = _make_counter() + +if __name__ == "__main__": + for _ in range(10): + fn_w_counter() + print(fn_w_counter()) From 046b87cb624fb09d05b00c7260356235a2f49562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleyna=20G=C3=BCltekin?= Date: Thu, 5 Nov 2026 15:00:00 +0300 Subject: [PATCH 5/5] Refactor calculations and add type validation Refactor function to include type checks and simplify code. --- Week04/functions_aleyna_gultekin.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/Week04/functions_aleyna_gultekin.py b/Week04/functions_aleyna_gultekin.py index dbd1894e..07f59ea4 100644 --- a/Week04/functions_aleyna_gultekin.py +++ b/Week04/functions_aleyna_gultekin.py @@ -18,31 +18,21 @@ def custom_equation(x: int = 0, y: int = 0, /, a: int = 1, b: int = 1, *, c: int :return: The calculated value :rtype: float """ - first_term = x ** a - second_term = y ** b - return float((first_term + second_term) / c) + for name, value in (("x", x), ("y", y), ("a", a), ("b", b), ("c", c)): + if type(value) is not int: + raise TypeError(f"{name} must be an int") + return float((x ** a + y ** b) / c) -def fn_w_counter() -> tuple[int, dict[str, int]]: +def fn_w_counter() -> (int, dict[str, int]): if not hasattr(fn_w_counter, "call_count"): fn_w_counter.call_count = 0 fn_w_counter.callers = {} - try: - raise Exception - except Exception as error: - caller = error.__traceback__.tb_frame.f_back.f_globals["__name__"] - fn_w_counter.call_count += 1 - if caller in fn_w_counter.callers: - fn_w_counter.callers[caller] += 1 + if __name__ in fn_w_counter.callers: + fn_w_counter.callers[__name__] += 1 else: - fn_w_counter.callers[caller] = 1 + fn_w_counter.callers[__name__] = 1 return fn_w_counter.call_count, fn_w_counter.callers - - -if __name__ == "__main__": - for _ in range(10): - fn_w_counter() - print(fn_w_counter())