Python « : » dekoratory do mierzenia czasu », ponawiania, buforowania i walidacji

Python ":" dekoratory do mierzenia czasu », ponawiania, buforowania i walidacji
3 min czytania

Dekoratory Pythona pozwalają dodać do funkcji wspólne zachowania, takie jak pomiar czasu, ponawianie prób, buforowanie czy walidacja argumentów, bez modyfikowania jej wewnętrznego kodu. W samouczku opublikowanym na Machine Learning Mastery autor szczegółowo opisuje ich działanie i pokazuje, jak zbudować niezawodne dekoratory, nie ukrywając przy tym wyjątków.

  • Dekoratory dodają funkcjom wspólne zachowania bez zmiany ich kodu.
  • Functools.wraps zachowuje nazwę i dokumentację oryginalnej funkcji.
  • Ponawianie prób jest bezpieczne tylko dla wywołań, które można wykonać dwukrotnie.
  • Dekorator nie powinien decydować o logice biznesowej funkcji.

Punktem wyjścia jest moduł przetwarzania danych składający się z trzech funkcji, które z czasem przejęły dodatkowe zadania. Według samouczka jedna funkcja sprawdza, czy ścieżka istnieje, zanim załaduje embeddingi, inna powtarza swoje żądania w pętli z użyciem time.sleep(), a trzecia mierzy swój czas wykonania i przechowuje wyniki w słowniku. Ten kod graniczny, dodany ręcznie, różni się między funkcjami, a każda nowa funkcja może wprowadzić własną wariację.

Dekorator – proste przypisanie

Dekorator to funkcja przyjmująca funkcję jako argument i zwracająca wrapper, czyli opakowanie wykonujące kod przed i po oryginalnym wywołaniu. Samouczek przypomina, że składnia @ jest równoważna ponownemu przypisaniu nazwy funkcji, co słownik Pythona nazywa cukrem składniowym. Dekorator jest więc wykonywany tylko raz, w momencie definiowania funkcji.

Wrapper zachowuje oryginalną funkcję dzięki domknięciu (closure) – mechanizmowi, w którym funkcja wewnętrzna zachowuje dostęp do zmiennych funkcji ją otaczającej. Parametry *args i **kwargs przekazują argumenty, a wynik jest zwracany bez zmian. Bez dodatkowych środków ostrożności wrapper zastępuje jednak nazwę i dokumentację funkcji. Samouczek zaleca więc użycie functools.wraps, który kopiuje te metadane, oraz atrybutu __wrapped__ umożliwiającego dostęp do funkcji niedekorowanej podczas testów.

Cztery zachowania graniczne

Dekorator pomiaru czasu opiera się na time.perf_counter(), zegarze służącym do obliczania odstępów czasu, a nie dat. Umieszczony w bloku try/finally, wyświetla czas trwania nawet gdy funkcja zawiedzie, a wyjątek jest przekazywany dalej do wywołującego.

Dekorator ponawiania prób jest fabryką akceptującą opcje takie jak max_attempts, delay oraz wyjątki do przechwycenia. Ponawia próby tylko dla skonfigurowanych wyjątków, aby błąd programistyczny nie był traktowany jak problem sieciowy. Przy ostatniej próbie, gołe raise ponownie zgłasza oryginalny wyjątek. Samouczek podkreśla jednak ograniczenie: to podejście jest bezpieczne tylko dla wywołań, które można wykonać dwukrotnie bez konsekwencji. Płatność czy wysyłka wiadomości nie spełniają tego kryterium.

W przypadku buforowania samouczek zaleca functools.lru_cache, który przechowuje wyniki najnowszych wywołań, do limitu maxsize (np. 256). Jego ograniczenia wynikają z implementacji: argumenty muszą być haszowalne, a funkcja zwracająca modyfikowalny obiekt może powodować nieoczekiwane efekty. Walidacja natomiast używa inspect.signature() do powiązania argumentów z nazwami parametrów, nawet gdy są przekazywane pozycyjnie lub z wartością domyślną, a następnie stosuje proste reguły przed wywołaniem.

Samouczek kończy się zasadą ostrożności: dekorator nie powinien decydować o logice biznesowej funkcji. Gdy zachowanie zależy od danych, lepiej umieścić je w samej funkcji lub w modelu danych dla walidacji. Gdy kilka dekoratorów jest ułożonych w stos, ich kolejność ma znaczenie, ponieważ najwyższy jest najbardziej zewnętrznym wrapperem.

S’abonner
Notification pour
guest

0 Commentaires
Le plus ancien
Le plus récent Le plus populaire
0
Nous aimerions avoir votre avis, veuillez laisser un commentaire.x