• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

OOP, tworzenie klas z długich funkcji

42 Warsaw Coding Academy
0 głosów
256 wizyt
pytanie zadane 18 lipca 2019 w Python przez RafalS VIP (122,820 p.)

Ostatnio piszę w pracy sporo skryptów do command-line'owego użycia i denerwowało mnie żmudne deklarowanie argparserów. Napisałem, więc skrypt do generowania argparsera na podstawie docstringa i adnotacji typów funkcji.

Funkcja mi się trochę rozbudowała i pasowałoby połączyć funkcje z danymi jakąś klasą. Jaki interfejs powinna mieć ta klasa?

Czy obiekt per funkcja do przetworzenia to dobry design:

ArgparserGenerator(foo).generate()
ArgparserGenerator(bar).generate()

czy lepszy jest reużywalny obiekt:

argparser_generator = ArgparserGenerator()
argparser_generator.generate(foo)
argparser_generator.generate(bar)

Czy może tworzyć obiekt per funkcje, ale klasę schować w funkcji jako szczegół implementacyjny:

def generate_argparser(func):
    return ArgparserGenerator(foo).generate()

 

1 odpowiedź

+2 głosów
odpowiedź 18 lipca 2019 przez adrian17 Mentor (353,220 p.)
wybrane 19 lipca 2019 przez RafalS
 
Najlepsza

A po co w ogóle klasa?

Czemu nie po prostu:

parser = generate_parser(foo)

Albo nawet, zakładając że zazwyczaj jego jedynym użyciem wygenerowanego argparsera będzie wywołanie na nim `.parse_args()`, to nawet

args = parse_args_from(foo)

Ostatnio piszę w pracy sporo skryptów do command-line'owego użycia i denerwowało mnie żmudne deklarowanie argparserów

Jeśli robisz to dla pracy, to raczej lepszym zużyciem zasobów czasowych będzie użycie gotowej biblioteki robiącej to, co chcesz - bo jest ich masa.

https://gist.github.com/supposedly/01224262b816df21b601ab0784d5f999

(btw, wygląda że `docopt` w zasadzie zrobił to samo, co zaproponowałem)

komentarz 18 lipca 2019 przez adrian17 Mentor (353,220 p.)
(plus osobista opinia: generowanie z docstringa wydaje się trochę dziwne, bo nie wyobrażam sobie by dało się tam zreprodukować wszystkie ficzery argparse'a.)
komentarz 18 lipca 2019 przez adrian17 Mentor (353,220 p.)

Jeszcze tylko dodam:

ArgparserGenerator(foo).generate()

To byłby raczej kandydat na refactor z klasy na funkcję, a nie na odwrót ;)

komentarz 18 lipca 2019 przez RafalS VIP (122,820 p.)

A po co w ogóle klasa?

Bo główna funkcja ma ~80 linijek i chciałem to jakoś pogrupować, a rozbijanie na małe funkcje bez klasy to znowu straszne programowanie proceduralne z przesyłaniem masy argumentów. A po to jest właśnie programowanie obiektowe żeby połączyć dane z funkcjami.

by dało się tam zreprodukować wszystkie ficzery argparse

Bo nie potrzebuje ich wszystkich, to ma uprościć żmudne przeklepywanie, help="", type="", required=False i action='store_true' dla booli.

A na dobrą sprawę wystarczy dodać dict jako drugi opcjonalny argument i można umożliwić dowolne dodatkowe/nadpisujące argumenty do add_argument, przez co jestem w stanie większość ficzerów wykorzystać.

Jeśli robisz to dla pracy, to raczej lepszym zużyciem zasobów czasowych

Nadarzyła się żadka okazja napisania czegoś ciekawszego w pythonie, a że naklepanie tego to pare godzin, więc skorzystałem.

komentarz 18 lipca 2019 przez RafalS VIP (122,820 p.)
Przyglądnę się jeszcze porządniej tej liście narzędzi, ale np taki docopt robi coś troszkę innego. Ja chcę mieć docstringi w kodzie i jednocześnie to samo w helpie skryptu jako command-line'owego toola.
komentarz 18 lipca 2019 przez adrian17 Mentor (353,220 p.)

Bo główna funkcja ma ~80 linijek

To nie jest aż tak długie. Na przykład pylint domyślnie zaczyna narzekać przy ponad 100 statementach w funkcji. Wyrzucić może parę małych funkcji pomocniczych na bok i będzie fajnie.

to znowu straszne programowanie proceduralne z przesyłaniem masy argumentów

Dla jednych to jest straszne, dla innych niepotrzebne OOP jest straszne. Python z założenia jest językiem wieloparadygmatowym, nie ma tu aż takiego nacisku na OOP ;)

No i jeszcze jedno: wewnętrzna organizacja kodu nie powinna dyktować zewnętrznego API. Jak jakiś inny "zewnętrzny" user zapyta dlaczego musi robić `ArgparserGenerator(foo).generate()` zamiast bezpośredniego `generate_argparse(foo)` i usłyszy że to żeby "nie przekazywać wewnątrz masy argumentów", to podrapie się po głowie.

komentarz 19 lipca 2019 przez RafalS VIP (122,820 p.)

wewnętrzna organizacja kodu nie powinna dyktować zewnętrznego API

Dlatego myślałem o ukryciu tej klasy w funkcji.

Dzięki za rady, zobaczę ile da sie wyciągnąć.

A co myślisz o takim patternie:

Funkcja generate_argparse, która robi tylko pare asercji i wywołuje _generate_argparse którą zajmuję sie prawdziwym generowaniem?

komentarz 19 lipca 2019 przez adrian17 Mentor (353,220 p.)

Funkcja generate_argparse, która robi tylko pare asercji i wywołuje _generate_argparse którą zajmuję sie prawdziwym generowaniem?

Brzmi OK.

Podobne pytania

0 głosów
3 odpowiedzi 481 wizyt
pytanie zadane 16 stycznia 2019 w Python przez niezalogowany
0 głosów
0 odpowiedzi 530 wizyt

93,377 zapytań

142,379 odpowiedzi

322,527 komentarzy

62,724 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...