Definiowanie funkcji ze zbyt dużą liczbą argumentów, aby przestrzegać standardu PEP8

Zdefiniowałem funkcję z długą listą argumentów. Całkowita liczba znaków w definicji jest powyżej 80 i nie jest zgodna z PEP8.

def my_function(argument_one, argument_two, argument_three, argument_four, argument_five):

Jakie może być najlepsze podejście, aby uniknąć poziomego przewijania?

 77
Author: Waldir Leoncio, 2014-07-28

7 answers

Przykład jest podany w PEP 8:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
Więc to jest oficjalna odpowiedź. Osobiście nienawidzę tego podejścia, w którym linie kontynuacyjne mają wiodące białe znaki, które nie odpowiadają żadnemu rzeczywistemu poziomowi wcięcia. Moje podejście to:
class Rectangle(Blob):

    def __init__(
        self, width, height,
        color='black', emphasis=None, highlight=0
    ):

. . . lub po prostu niech linia biegnie ponad 80 znaków.

 112
Author: BrenBarn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-28 04:17:44

Dla kodu Pythona, który używa typu adnotacje , proponuję to:

def some_func(
    foo: str,
    bar: str = 'default_string',
    qux: Optional[str] = None,
    qui: Optional[int] = None,
) -> List[str]:
    """
    This is an example function.
    """
    print(foo)
    ...

Jeśli używasz yapf możesz użyć tych opcji w .style.yapf:

[style]
dedent_closing_brackets = true
split_arguments_when_comma_terminated = true
 20
Author: Rotareti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-03 09:43:00

Osobiście też wymyśliłem to samo rozwiązanie co drugi styl @BrenBarn. Podoba mi się jego sposób, aby właściwie reprezentować wcięcie parametrów funkcji i jej implementację, chociaż ta "nieszczęśliwa twarz" jest nieco nietypowa dla niektórych innych ludzi.

Obecnie, PEP8 konkretnie daje przykład na taki przypadek, więc być może mainstream dostosuje ten styl:

    # Add 4 spaces (an extra level of indentation)
    # to distinguish arguments from the rest.
    def long_function_name(
            var_one, var_two, var_three,
            var_four):
        print(var_one)

Możemy oczywiście pójść o krok dalej, rozdzielając każdy parametr na jego własny linia, tak aby każde przyszłe dodanie / usunięcie parametru dawało czyste git diff:

    # Add 4 spaces (an extra level of indentation)
    # to distinguish arguments from the rest.
    def long_function_name(  # NOTE: There should be NO parameter here
            var_one,
            var_two,
            var_three,
            var_four,  # NOTE: You can still have a comma at the last line
            ):  # NOTE: Here it aligns with other parameters, but you could align it with the "def"
        print(var_one)
 14
Author: RayLuo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-10 22:45:18

1. Co polecam

Chociaż sprawia, że funkcja jest bardziej wyrazista, dla więcej niż jednego argumentu , myślę, że jest to najlepsze-poniższy przykład pochodzi z Python -:

def my_function(
    argument_one, 
    argument_two, 
    argument_three,
    argument_four, 
    argument_five,
):
    ...

2. Dlaczego?

  1. posiadanie każdego argumentu w jednej linii sprawia, że korzystanie z git diffs jest bardzo proste, ponieważ zmiana jednej zmiennejpokaże tylko , że się zmienia. Jeśli masz więcej niż jeden argument w każdej linii, to będzie bardziej irytujące wizualnie później.
    • zawiadomienie to, że końcowy przecinek po ostatnim argumencie ułatwia późniejsze dodanie lub usunięcie argumentu, a jednocześnie jest zgodny z Konwencją PEP 8 ' S Trailing Comma i daje lepsze git diff później.
  2. jednym z powodów, dla których naprawdę nie lubię paradygmatu" wyrównaj argumenty z nawiasem otwierającym", jest to, że nie daje łatwego do utrzymania kodu.
    • Kevlin Henney wyjaśnia to jest złą praktyką w jego ITT 2016-siedem nieskutecznych nawyków kodowania wielu programistów (ok. 17:08).
    • głównym powodem, dla którego jest to zła praktyka jest to, że jeśli zmienisz nazwę funkcji (lub jeśli jest zbyt długa), będziesz musiał ponownie edytować odstępy na wszystkich linii argumentów, które w ogóle nie są skalowalne, choć może być (czasami) (subiektywnie ) ładniejsza.
    • drugi powód, ściśle związany z tym bezpośrednio powyżej, jest o metaprogramowanie. Jeśli baza kodu stanie się zbyt duża, w końcu będziesz musiał zaprogramować zmiany w samym pliku kodu, które mogą stać się piekłem , Jeśli odstępy na argumentach są różne dla każdej funkcji.
  3. Większość edytorów, po otwarciu nawiasów i naciśnięciu enter , otworzy nowy wiersz z zakładką i przesunie nawias zamykający do następnego wiersza, nieabbowanego. Tak więc formatowanie kodu w ten sposób jest bardzo szybkie i miłe znormalizowanych. Na przykład formatowanie to jest bardzo powszechne w JavaScript i Dart.
  4. wreszcie, jeśli uważasz, że posiadanie każdego argumentu jest zbyt nieporęczne, ponieważ twoja funkcja może mieć dużo argumentów , powiedziałbym, że kompromitujesz łatwe formatowanie kodu z powodu rzadkich WYJĄTKÓW.
    • nie ustawaj według WYJĄTKÓW .
    • jeśli twoja funkcja ma dużo argumentów, prawdopodobnie robisz coś złego. Przełam na więcej (pod)funkcje i (pod)klasy.

3. W każdym razie...

Dobra konwencja jest lepsza niż zła, ale jest o wiele ważniejsze, aby ją egzekwować, niż być niepotrzebnie wybrednym w stosunku do nich .

Gdy już zdecydujesz się na użycie standardu, podziel się swoją decyzją z kolegami i użyj automatycznego formatowania - na przykład ładniejszy jest popularnym wyborem dla JavaScript w VS Code; a język Dart ustandaryzował jeden globalnie: dartfmt - konsekwentnie go egzekwować, zmniejszając potrzebę ręcznej edycji.

 12
Author: Philippe Fanaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-27 13:45:43
def my_function(argument_one, argument_two, argument_three, 
                argument_four, argument_five):
 11
Author: kylieCatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-28 03:51:50

Osobiście lubię ustawiać params jeden na wiersz, zaczynając od otwartych nawiasów i zachowując to wcięcie. Wydaje się być z tego zadowolony.

def guess_device_type(device_name: str,
                      username: str=app.config['KEY_TACACS_USER'],
                      password: str=app.config['KEY_TACACS_PASS'],
                      command: str='show version') -> str:
    """Get a device_type string for netmiko"""
 4
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 22:31:19

Uważam się za dość interesującego:

def my_function(
        argument_one, argument_two, argument_three,
        argument_four, argument_five
):
    ...

Pozwala na składanie kodu, aby dość łatwo ujawnić sygnatury funkcji, na przykład rozważ poniższy fragment:

def my_function(
        argument_one, argument_two, argument_three,
        argument_four, argument_five
):
    s1 = 1
    s2 = 2
    if s1 + s2:
        s3 = 3


def my_other_function(argument_one, argument_two, argument_three):
    s1 = 1
    s2 = 2
    if s1 + s2:
        s3 = 3

W ten sposób można złożyć kod-cały plik i zobaczyć wszystkie funkcje / sygnatury naraz, czyli:

Tutaj wpisz opis obrazka

 4
Author: BPL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-25 14:38:59