Skip to content

Commit af6dcc3

Browse files
fix: changed return annotation to test requirements
1 parent 313c8ef commit af6dcc3

File tree

2 files changed

+77
-57
lines changed

2 files changed

+77
-57
lines changed
Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,52 @@
1+
from __future__ import annotations
2+
13
import time
24
import tracemalloc
3-
import functools
4-
5-
def performance(func):
6-
"""
7-
Fonksiyonun performansını ölçen ve istatistiklerini saklayan dekoratör.
8-
"""
9-
if not hasattr(performance, "counter"):
10-
performance.counter = 0
11-
performance.total_time = 0.0
12-
performance.total_mem = 0
13-
14-
@functools.wraps(func)
15-
def wrapper(*args, **kwargs):
16-
tracemalloc.start()
17-
start_time = time.perf_counter()
18-
result = func(*args, **kwargs)
19-
end_time = time.perf_counter()
20-
21-
current_mem, peak_mem = tracemalloc.get_traced_memory()
22-
tracemalloc.stop()
23-
24-
performance.counter += 1
25-
performance.total_time += (end_time - start_time)
26-
performance.total_mem += peak_mem
5+
from functools import wraps
6+
from typing import Any, Callable, TypeVar, cast
7+
8+
F = TypeVar("F", bound=Callable[..., Any])
9+
10+
11+
def performance(func: F) -> F:
12+
13+
@wraps(func)
14+
def wrapper(*args: Any, **kwargs: Any) -> Any:
15+
# ensure stats exist
16+
wrapper.counter += 1 # type: ignore[attr-defined]
17+
18+
# time
19+
t0 = time.perf_counter()
20+
21+
# memory (tracemalloc)
22+
tracing_already = tracemalloc.is_tracing()
23+
if not tracing_already:
24+
tracemalloc.start()
25+
26+
before_current, before_peak = tracemalloc.get_traced_memory()
27+
try:
28+
result = func(*args, **kwargs)
29+
finally:
30+
after_current, after_peak = tracemalloc.get_traced_memory()
31+
dt = time.perf_counter() - t0
32+
33+
wrapper.total_time += dt # type: ignore[attr-defined]
34+
35+
# Use peak delta as "consumed" approximation for this call
36+
delta_peak = after_peak - before_peak
37+
if delta_peak < 0:
38+
delta_peak = 0
39+
wrapper.total_mem += int(delta_peak) # type: ignore[attr-defined]
40+
41+
# Don't disrupt global tracing if it was already enabled
42+
if not tracing_already:
43+
tracemalloc.stop()
2744

2845
return result
2946

30-
return wrapper
47+
# required attributes
48+
wrapper.counter = 0 # type: ignore[attr-defined]
49+
wrapper.total_time = 0.0 # type: ignore[attr-defined]
50+
wrapper.total_mem = 0 # type: ignore[attr-defined]
3151

32-
performance.counter = 0
33-
performance.total_time = 0.0
34-
performance.total_mem = 0
52+
return cast(F, wrapper)

Week04/functions_furkan_cetiner.py

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
1+
from __future__ import annotations
2+
13
import inspect
4+
from typing import Any, Dict, Tuple
5+
26

3-
# 1. custom_power: lambda function with positional-only x
47
custom_power = lambda x=0, /, e=1: x**e
58

6-
# 2. custom_equation: positional-only, positional-or-keyword, and keyword-only params
9+
710
def custom_equation(x: int = 0, y: int = 0, /, a: int = 1, b: int = 1, *, c: int = 1) -> float:
8-
"""
9-
Calculates (x**a + y**b) / c with specific parameter constraints.
10-
:param x: Base 1, positional-only
11-
:param y: Base 2, positional-only
12-
:param a: Exponent 1, positional-or-keyword
13-
:param b: Exponent 2, positional-or-keyword
14-
:param c: Divisor, keyword-only
15-
:returns: Result as float
16-
"""
17-
return float((x**a + y**b) / c)
18-
19-
# 3. fn_w_counter: tracks total calls and caller names
20-
def fn_w_counter() -> (int, dict[str, int]):
21-
"""
22-
Counts the number of calls and tracks the caller (__name__).
23-
"""
24-
if not hasattr(fn_w_counter, "calls"):
25-
fn_w_counter.calls = 0
26-
fn_w_counter.callers = {}
27-
28-
caller_frame = inspect.currentframe().f_back
29-
caller_name = caller_frame.f_globals.get('__name__', 'unknown')
30-
31-
fn_w_counter.calls += 1
32-
fn_w_counter.callers[caller_name] = fn_w_counter.callers.get(caller_name, 0) + 1
33-
34-
return (fn_w_counter.calls, fn_w_counter.callers)
11+
12+
return (x**a + y**b) / c
13+
14+
15+
def fn_w_counter() -> Tuple[int, Dict[str, int]]:
16+
17+
18+
if not hasattr(fn_w_counter, "_total"):
19+
fn_w_counter._total = 0 # type: ignore[attr-defined]
20+
if not hasattr(fn_w_counter, "_by_caller"):
21+
fn_w_counter._by_caller = {} # type: ignore[attr-defined]
22+
23+
24+
frame = inspect.currentframe()
25+
caller_frame = frame.f_back if frame is not None else None
26+
caller_name = "<unknown>"
27+
if caller_frame is not None:
28+
caller_name = str(caller_frame.f_globals.get("__name__", "<unknown>"))
29+
30+
31+
fn_w_counter._total += 1 # type: ignore[attr-defined]
32+
by_caller: Dict[str, int] = fn_w_counter._by_caller # type: ignore[attr-defined]
33+
by_caller[caller_name] = by_caller.get(caller_name, 0) + 1
34+
35+
36+
return int(fn_w_counter._total), dict(by_caller) # type: ignore[attr-defined]

0 commit comments

Comments
 (0)