Jak mam nazwać funkcje zwracające wartości w Pythonie?

13

Nie jestem pewien, czy wybieram nazwy dla moich funkcji w Pythonie . Czasami niezbędne są funkcje wbudowane w Python , takie jak: printfunkcja i metoda łańcuchowa find. Czasami nie są tacy, jak: lenjego nazwa nie jest niezbędna, jak calculate_lenna przykład i typenie jest find_type.

Rozumiem, że printzwraca wartość, której nie używamy (tj. None) I robi coś (tj. Pokazuje ciąg znaków na ekranie), więc jej nazwa jest bezwzględna.

Ale lenzwraca wartość, że używamy i robi coś (czyli obliczenie ile przedmiotów istnieją w sekwencji lub mapowania.), A jego nazwa nie jest konieczne . Z drugiej strony findmetoda string (as len) zwraca wartość, której używamy i robi coś, a jej nazwa jest bezwzględna .

To, co sprawiło, że zadałem to pytanie, polega na tym, że poddałem przeglądowi skrypt, który szyfruje i odszyfrowuje ciąg przy użyciu szyfru Cezara. Recenzent powiedział, że:

Po prostu przeczucie: funkcje robią różne rzeczy. Dobra nazwa funkcji jest więc niezbędna: użyłbym rotate_letterzamiast rotated_letter.

rotated_letterzwraca ciąg jednoliterowy reprezentujący literę obróconą o liczbę. Nie wiem, co jest lepsze, użyłem, rotated_letterponieważ zwraca wartość, jak randintfunkcja w module losowym , nie jest generate_randint.

Więc w takim przypadku, jak mam nazwać funkcję, która zwraca wartość, która ma być użyta? Powinienem uczynić nazwę imperatywną, czy tylko rzeczownikiem . W innych przypadkach jest oczywiste, jak to zrobić, takie jak funkcje boolowskie , takie jak is_eveni is_palindromepo prostu sprawiamy, że jest to pytanie typu tak / nie , a także funkcje, które tylko wykonują i zwracają nieużywane wartości (tj. None), Takie jak printi metoda list sort.

Mahmood Muhammad Nageeb
źródło
jest to w rzeczywistości bardzo powszechna praktyka (powiedziałbym, że konwencja) używania imperatywów podczas nazywania funkcji. Na przykład, jak nazwać zmienną, która przechowuje obróconą literę funkcji rotated_letter?
JoulinRouge,
To nie jest dobry sposób myślenia o niektórych z twoich przykładów. len, na przykład, lepiej jest traktować go jako „długość” - otrzymujesz opis jego argumentu na poziomie meta.
Izkata,

Odpowiedzi:

10

Używaj czasowników tam, gdzie jest to uzasadnione, rzeczowników, jeśli są one krótsze i jednoznaczne

Przez większość czasu funkcjami powinny być (imperatywne) czasowniki, a klasy, zmienne i parametry powinny być rzeczownikami. Atrybutami powinny być także rzeczowniki, w tym te utworzone przy użyciu @property. Dotyczy to zwłaszcza funkcji wywołujących skutki uboczne. [1] Jeśli funkcja coś zwraca, powinieneś ocenić, czy czasownik coś dodaje, czy jest po prostu „szumem”:

  • make_list(foo)vs list(foo).: Rzeczownik jest łatwiejszy do odczytania niż czasownik. Poza tym listjest właściwie klasą, a klasy powinny być rzeczownikami.
  • open(foo)vs file(foo).: Czasownik jest łatwiejszy do odczytania niż rzeczownik, i sensowniejsze jest dawanie „opcji” czasownikowi niż rzeczownikowi, więc rzeczownik został usunięty w Pythonie 3. open()pozostaje jedynym „standardowym” [2] sposobem do tworzenia obiektów plików w Pythonie 3.
  • foo.get_bar()vs foo.bar()vs foo.bar(zakładamy, fooi barto zarówno rzeczowniki): Pierwsza opcja jest prosto, bo „dostać” nie dodaje nic, że już nie wiem. Drugi jest odpowiedni, jeśli wydostanie barsię z foojest potencjalnie kosztowną operacją i / lub niesie ze sobą skutki uboczne (możesz również rozważyć, Bar(foo)czy Barjest to klasa). Trzeci jest odpowiedni, jeśli jest to tania operacja bez skutków ubocznych, a alternatywne wdrożenia raczej nie spowodują, że będzie kosztowna .
  • xs.sort()vs. sorted(xs)if xsjest listą: pierwszy jest konieczny: posortuj listę. Zmienia listę w miejscu i nic nie zwraca. Drugi jest deklaratywny: lista jest posortowana, czyli dokładnie to, co zwraca. Oba są czasownikami.

[1]: Zwykle zwracanie wartości i wywoływanie efektów ubocznych wykluczają się nawzajem, chyba że masz ważny powód, aby je połączyć. Tak więc funkcja, która ma skutki uboczne, prawdopodobnie nie powinna niczego zwracać, a zatem uczynienie z niej rzeczownika nie miałoby większego sensu.
[2]: W iomodule znajduje się kilka operacji na niższym poziomie , które można wykorzystać do dodawania lub usuwania buforowania plików, automatycznego en / dekodowania tekstu itp., I są to w większości rzeczowniki, ponieważ są to klasy obiektowe. Większość użytkowników nie musi bezpośrednio bawić się tymi rzeczami; zamiast tego open()wybiera odpowiednią klasę i tworzy ją automatycznie.

Kevin
źródło
Dziękuję Ci! W " foo.get_bar() vs.` foo.bar ()` vs. foo.bar" jaka jest różnica między drugim a trzecim ?
Mahmood Muhammad Nageeb
Trzeci to albo własność, albo zwykły atrybut. Drugi to metoda.
Kevin
Tak więc, jeśli rozumiem, nie należy wprowadzać rotated_letternakazu i utrzymywać go w porządku, prawda?
Mahmood Muhammad Nageeb
W tym przypadku nie jestem pewien, czy letterwynika to z kontekstu.
Kevin
+1 za wzmiankę listto klasa
Dušan Maďar
0

rotated_letternie wygląda jak metoda. Wygląda jak własność. Co oznacza, że ​​pierwszym pomysłem jest:

var letter = caesar.rotated_letter

oczekiwanie, że letterbędzie zawierać wartość typu string, a nie funkcję. Następnie wybierz inną nazwę, na przykład:

def rotate_letter(self):
    pass

lub zamiast tego korzystasz z nieruchomości:

@property
def rotated_letter(self):
    return self.whatever

leni typesą tak nazywane, ponieważ każda inna nazwa będzie długa do wpisania. Są często używane i mają specjalny status podstawowych funkcji Pythona, których i tak nauczy się każdy programista Pythona, przez co ich nazwy są znacznie bardziej nieistotne niż nazwy bibliotek stron trzecich.

len, Szczególnie, jest dobrym przykładem tego, co nie należy robić w swoim kodzie: jesteś oczekuje się używać pełnych nazw, takich jak length(chyba, że krótka forma jest bardzo popularne, takie jak max) i użyć czasownika, np compute_length. Lub może to być właściwość: len([1, 5, 6])staje się [1, 5, 6].length. Na przykład, w c #, później postać stosuje się: new [] { ... }.Length.

Należy pamiętać, że mogą istnieć również powody historyczne len: preferowane są inne języki, takie jak C # Count, co zwykle jest metodą (chociaż zachowanie jest niestety niespójne w .NET Framework). Countjest czasownikiem, więc intuicyjnie masz skłonność do inwokowania go jako metody.

Zwracanie wartości lub wykonywanie akcji

Zawsze oczekuje się, że funkcja wykona akcję. Jeśli ledwo zwraca wartość, powinna być właściwością. Masz wskazówkę, że funkcję należy przekształcić we właściwość, gdy:

  • Funkcja ledwo zawiera return ...instrukcję,

  • Nazwa funkcji, która naturalnie pojawia się w twoim umyśle, jest get_somethingjak w product.get_price().

Teraz, jeśli masz funkcję, może to być jeden z czterech typów:

  • Może być czysty, to znaczy zwraca wartość bez wpływu na środowisko. Przykład: road.measure_distance().

  • Może wpływać na środowisko bez zwracania czegokolwiek. Przykład: product_database.remove_record(1234).

  • Może wpływać na środowisko i zwracać wartość. Przykład: value.increment()używane, takie jak value++.

  • Nic nie może zrobić i nic nie zwraca. Przykład: time.sleep(1).

Istnieje kilka przypadków, w których nazwa może dać silną wskazówkę na temat rodzaju funkcji, ale w wielu przypadkach nie będziesz w stanie poznać typu z jego nazwy.

Arseni Mourzenko
źródło
Zakładam, że odpowiedź brzmi „tak”, ale muszę zapytać: czy odpowiadasz całkowicie z perspektywy Pythona? Ponieważ w innych językach twój podział funkcji na własność nie zawsze jest prawdziwy; nie jest również prawdą, że funkcja „musi wykonać akcję”. Czy to konwencja w Pythonie? (Piszę w Pythonie, ale nie przeczytałem wszystkich PEP i zdecydowanie NIE jestem ekspertem. Nie głosowałem, BTW).
Andres F.,
@AndresF .: Odpowiadam z perspektywy Pythona. W językach takich jak Java, w których właściwości nie istnieją, getSomethingi setSomethingsą to zwykłe nazwy używane zamiast właściwości.
Arseni Mourzenko,