Dlaczego średnik jest dozwolony w tym fragmencie kodu Pythona?

166

Python nie gwarantuje użycia średników na końcu instrukcji. Dlaczego więc jest to (poniżej) dozwolone?

import pdb; pdb.set_trace()
canadadry
źródło
1
Zauważ, że taki kod jest rażąco tylko do celów debugowania i prawdopodobnie zostałby wycięty, zanim zostanie „ukończony”. Używam tego fragmentu tak, jak go masz, więc mogę go łatwo przenosić.
Nick T
Lol Doszedłem do tego pytania z tej samej witryny: realpython.com/python-debugging-pdb
mackycheese 21

Odpowiedzi:

226

Python nie wymaga średników do zakończenia instrukcji. Średnikiem mogą być wykorzystywane do ograniczania wypowiedzi, jeśli chcesz umieścić wiele instrukcji w tej samej linii.

Teraz, dlaczego jest to dozwolone? To prosta decyzja projektowa. Myślę, że Python nie potrzebuje tego średnika, ale ktoś pomyślał, że fajnie byłoby go mieć i dodał do języka.

André Caron
źródło
16
Przydaje się do takich rzeczy jaktimeit a = 5; a*a
endolith
13
Wydaje się przydatne dla instrukcji exec, np. Exec ('for a in [1,2,3]: print a; print a + 1')
Phil C
76
Przyszedłem do Pythona ze znajomością C, Obj-C, Javascript, PHP. Często umieszczam (bezużyteczny) terminator; na końcu wiersza. Ale na szczęście Python mi wybacza
Paolo
36
Średnik jest bardzo przydatny w powłoce django lub w debugerze, więc możesz napisać mały program w jednej linii i powtórzyć go później.
Bryce
5
@endolith Co timeitznaczy? a = 2; a*ajest bezużyteczny, ponieważ anadal jest 2; to musiało byća = 2; a *= a
Nearoo
59

http://docs.python.org/reference/compound_stmts.html

Instrukcje złożone składają się z co najmniej jednej „klauzuli”. Klauzula składa się z nagłówka i „zestawu”. Wszystkie nagłówki klauzul określonej instrukcji złożonej znajdują się na tym samym poziomie wcięcia. Każdy nagłówek klauzuli zaczyna się od jednoznacznie identyfikującego słowa kluczowego i kończy się dwukropkiem. Zestaw to grupa instrukcji kontrolowanych przez klauzulę. Zestaw może składać się z jednej lub więcej prostych instrukcji oddzielonych średnikami w tym samym wierszu, co nagłówek, po dwukropku nagłówka, lub może to być jedna lub więcej instrukcji z wcięciem w kolejnych wierszach . Tylko ta ostatnia forma zestawu może zawierać zagnieżdżone instrukcje złożone; poniższe jest niezgodne z prawem, głównie dlatego, że nie byłoby jasne, do której klauzuli należałaby następująca klauzula else:

if test1: if test2: print x

Zwróć także uwagę, że średnik wiąże się mocniej niż dwukropek w tym kontekście, więc w poniższym przykładzie wykonywane są wszystkie instrukcje print lub żadna z nich:

if x < y < z: print x; print y; print z 

Zreasumowanie:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | decorated
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]
chown
źródło
4
Nie wiedziałem, że priorytet średnika jest mniejszy niż dwukropek po if. Dzięki!
gaborous
3
@gaborous Osobiście czuję, że twój komentarz jest na tyle niejednoznaczny, że pomyślałem, że miałbyś na myśli odwrotnie. Tak więc, dla wyjaśnienia, wolałbym raczej zasugerować innym czytelnikom, aby trzymali się oficjalnego sformułowania: w tym if cond: stmt1; stmt2; stmt3przykładzie wszystkie lub żadne z oświadczeń nie są wykonywane ”.
RayLuo
Tak, o to mi chodziło, jeśli priorytet jest mniejszy, lekser nie może opuścić bloku nadrzędnego (dwukropka), dopóki nie zostaną wykonane wszystkie instrukcje średnika. To naprawdę nie jest oczywiste.
gaborous
38

Python używa znaku ;jako separatora, a nie terminatora. Możesz ich również użyć na końcu linii, co sprawia, że wyglądają jak terminator instrukcji, ale jest to dozwolone tylko dlatego, że puste instrukcje są dozwolone w Pythonie - linia zawierająca średnik na końcu to dwie instrukcje, druga jeden pusty.

kindall
źródło
28
Jeśli umieścisz podwójne średniki na końcu (lub gdziekolwiek), otrzymasz SyntaxError. Więc wydaje się, że puste stwierdzenia nie są całkowicie legalne.
Cucu
10
Prawdopodobnie ma tę samą logikę co listy, krotki, dykty z końcowymi przecinkami są prawidłowe i takie same jak ich przycięte odpowiedniki (np. [1,2,3] == [1,2,3,]) ale nie mogą zawierać podwójnych przecinków . Tak więc w zasadzie Python ma „końcowe narzędzie do usuwania pustych znaków”. Co, nawiasem mówiąc, wynika z tego:stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
Cucu
@Cucu Masz rację. Nie możesz również zaczynać wiersza średnikiem ani rozpoczynać listy wyrażeń przecinkiem. Dlatego dokładniej jest powiedzieć, że średniki i przecinki to separatory i opcjonalne terminatory.
wjandrea
29

Średnik w tłumaczu

Po przeczytaniu odpowiedzi nadal brakuje mi jednego ważnego aspektu używania średników, być może jedynego, w którym to naprawdę robi różnicę ...

Kiedy pracujesz z interpreterem REPL (interaktywna powłoka Pythona, IDLE, ipython), wartość ostatniego wyrażenia jest drukowana na ekranie i zazwyczaj jest to zamierzone zachowanie.

Używanie wyrażenia określającego skutki uboczne

Ale w niektórych przypadkach chcesz ocenić wyrażenie tylko pod kątem jego skutków ubocznych, np. Aby zobaczyć wykres wyników symulacji przez matplotlib.

W tych przypadków (prawdopodobnie) nie chcą, aby zobaczyć pełnoekranowa reprs od matplotlibobiektów, które czasami są zwracane przez wywołanie matplotlibfunkcji, a ipython przynajmniej jedną z możliwości masz jest dołączyć średnik do nadmiernie instrukcji verbose , teraz IPython widzi wiersz wejściowy jako złożony z dwóch wyrażeń, matplotlibwywołania i instrukcji null, tak że wartość wyrażenia złożonego jest Nonei nic nie jest drukowane na ekranie przez interpreter (drugą możliwością jest przypisanie , jak w _ = plot(...)ale uważam, że jest to trochę bardziej uciążliwe).

Osobista przymówka

IMHO, użycie średnika w celu wyeliminowania niepożądanego wyniku w tłumaczu stało się bardziej istotne po wprowadzeniu notatnika IPyton, który umożliwia zapisywanie danych wejściowych i wyjściowych, w tym danych wyjściowych graficznych, sesji tłumacza w celu dokumentacji i ewentualnego ponownego wykorzystania .

gboffi
źródło
Rozumiem, dziękuję za udostępnienie! To właśnie rozwiązało dokładnie mój problem, w którym średnik może zapobiec powtórzeniu przez matplotlib w notatniku
ipython
Jest to funkcja dostępna tylko w IPythonie i nie jest to instrukcja pusta, a jedynie specjalna składnia.
wjandrea
@wjandrea Masz rację, po prostu ipython... Zredagowałem moją odpowiedź, aby odzwierciedlić Twoją uwagę.
gboffi
Ta odpowiedź powinna być wyższa, ponieważ myślę, że stała się najczęstszym przypadkiem użycia (wraz z rozprzestrzenianiem się notebooka Jupyter + przepływ pracy IPython)
Josh Friedlander
12

Jak wszyscy zauważyli, do oddzielania zdań można używać średników. Nie musisz i to nie jest zwykły styl.

Jeśli chodzi o to, dlaczego jest to przydatne, niektórzy ludzie lubią umieszczać dwa lub więcej naprawdę trywialnych krótkich stwierdzeń w jednym wierszu (osobiście uważam, że zamienia to kilka trywialnych, łatwych do przejrzenia wierszy w jedną skomplikowaną linię i utrudnia dostrzeżenie, że jest to trywialne) .

Ale jest to prawie wymóg, gdy wywołujesz Python one liners z powłoki używając python -c '<some python code>'. Tutaj nie możesz używać wcięć do oddzielania instrukcji, więc jeśli twój jednolinijkowy jest naprawdę dwuwierszowy, musisz użyć średnika. A jeśli chcesz użyć innych argumentów w swoim jednolinijkowym, musisz zaimportować, sysaby uzyskać dostęp sys.argv, co wymaga osobnego importoświadczenia. na przykład

python -c "import sys; print ' '.join(sorted(sys.argv[1:]))" 5 2 3 1 4
1 2 3 4 5
Ben
źródło
2
Państwo może użyć wcięcia i nowe linie podczas przechodzenia przez polecenia pythonw powłoce: Just rozciągać swoją cytowany przez wielu linii kodu lub użyć heredoc. Jednak to zawodzi, jeśli chcesz, aby był to „jednolinijkowy”. ;)
00dani
zawiera cechy odpowiedzi kolejowej z-c
n611x007
6

Zdaję sobie sprawę, że jako stary programista C jestem stronniczy, ale są chwile, kiedy różne konwencje Pythona utrudniają przestrzeganie pewnych zasad. Czasami uważam, że konwencja wcięć jest trochę irytująca.

Czasami bardzo przydatna jest jasność, kiedy kończy się instrukcja lub blok. Standardowy kod C często czyta coś takiego:

for(i=0; i<100; i++) {
    do something here;
    do another thing here;
}

continue doing things;

gdzie używasz białych znaków dla większej przejrzystości - i łatwo jest zobaczyć, gdzie kończy się pętla.

Python pozwala na zakończenie (opcjonalnym) średnikiem. Jak wspomniano powyżej, NIE oznacza to, że istnieje instrukcja do wykonania, po której następuje instrukcja „null”. I tak na przykład

print(x);
print(y);

Jest taki sam jak

print(x)
print(y)

Jeśli uważasz, że pierwsza z nich zawiera instrukcję zerową na końcu każdej linii, spróbuj - zgodnie z sugestią - zrobić to:

print(x);;

Spowoduje to zgłoszenie błędu składniowego.

Osobiście uważam, że średnik sprawia, że ​​kod jest bardziej czytelny, gdy masz dużo zagnieżdżeń i funkcji z wieloma argumentami i / lub argumentami o długich nazwach. Tak więc, moim zdaniem, jest to o wiele jaśniejsze niż inne opcje:

if some_boolean_is_true:
    call_function(
        long_named_arg_1,
        long_named_arg_2,
        long_named_arg_3,
        long_named_arg_4
    );

ponieważ, dla mnie, pozwala ci wiedzieć, że ostatni „)” kończy pewien „blok”, który obejmował wiele linii.

Osobiście uważam, że jest zbyt wiele wytycznych dotyczących stylu PEP, IDE, które je egzekwują, oraz przekonania, że ​​jest „tylko jeden sposób robienia rzeczy w Pythonie”. Jeśli wierzysz w to drugie, zobacz, jak formatować liczby: w tej chwili Python obsługuje cztery różne sposoby, aby to zrobić.

Jestem pewien, że niektórzy zagorzali mnie podpalą, ale kompilator / interpreter nie dba o to, czy argumenty mają długie czy krótkie nazwy, i - poza konwencją wcięć w Pythonie - nie przejmuje się białymi znakami. Największym problemem związanym z kodem jest udzielenie jasności drugiemu człowiekowi (a nawet sobie po miesiącach pracy), aby zrozumiał, co się dzieje, gdzie zaczyna się i kończy itd.

eSurfsnake
źródło
5

Cytat z „ When Pythons Attack

Nie kończ wszystkich swoich instrukcji średnikiem. Z technicznego punktu widzenia jest to legalne w Pythonie, ale jest całkowicie bezużyteczne, chyba że umieścisz więcej niż jedną instrukcję w jednym wierszu (np. X = 1; y = 2; z = 3).

Communist Pancake
źródło
4
Dlaczego nie x,y,z = 1,2,3?
Anirban Nag 'tintinmj'
5
@ AnirbanNag'tintinmj 'W tym konkretnym przypadku uważam, że x, y, z = 1, 2, 3jest wolniejszy, ponieważ pociąga za sobą niepotrzebną podróż w obie strony w budowaniu krotki, a następnie natychmiast ją desembluje. (Nawiasem mówiąc, nie sądzę, żeby @communistpancake sugerował x=1; y=2; z=3wzorzec. Myślę, że on / ona podaje jedynie przykład tego, jak średnik jest raczej separatorem niż terminatorem.)
RayLuo
1
@AnirbanNag - ponieważ byłby to kiepski przykład linii zawierającej wiele instrukcji.
cz
3

Python umożliwia użycie średnika do oznaczenia końca instrukcji, jeśli w wierszu znajduje się więcej niż jedna instrukcja.

Godwin
źródło
2

Średniki mogą być używane w jednym wierszu, w którym znajdują się dwa lub więcej poleceń. Nie muszą być używane, ale nie są ograniczone.

Średnik (;) pozwala na umieszczanie wielu instrukcji w jednym wierszu, pod warunkiem, że żadna z instrukcji nie rozpoczyna nowego bloku kodu.

http://www.tutorialspoint.com/python/python_basic_syntax.htm

craniumonempty
źródło
2

Średniki (takie jak kropki, przecinki i nawiasy) mają tendencję do wywoływania wojen religijnych. Mimo to one (lub podobny symbol) są przydatne w każdym języku programowania z różnych powodów.

  • Praktyczne: możliwość umieszczenia kilku krótkich poleceń, które koncepcyjnie pasują do siebie w tej samej linii. Tekst programu, który wygląda jak wąski wąż, ma odwrotny skutek do tego, co zakładają znaki nowej linii i wcięcia, czyli podkreślenie struktury.

  • Konceptualny: oddzielenie obaw między czystą składnią (w tym przypadku dla sekwencji poleceń) od prezentacji (np. Nowa linia), w dawnych czasach nazywane „ładnym drukowaniem”.

Obserwacja: w celu podkreślenia struktury wcięcia można w oczywisty sposób zwiększyć / zastąpić pionowymi liniami, służąc jako „wizualna linijka”, aby zobaczyć, gdzie wcięcie się zaczyna i kończy. Różne kolory (np. Zgodne z kodem kolorów dla rezystorów) mogą kompensować gromadzenie się.

Raymond
źródło
1

Jest to dozwolone, ponieważ autorzy zdecydowali się na to zezwolić: https://docs.python.org/2/reference/simple_stmts.html

Jeśli przejdziesz do pytania, dlaczego autorzy zdecydowali się tak zrobić, myślę, że tak jest, ponieważ półkolumna jest dozwolona jako proste zakończenie instrukcji przynajmniej w następujących językach: C ++, C, C #, R, Matlab, Perl, ...

Dzięki temu łatwiej jest zacząć używać Pythona dla osób z doświadczeniem w innym języku. W takim deicisonie nie ma utraty ogólności.

bruziuz
źródło
1

Średnik („;”) jest potrzebny tylko do oddzielenia instrukcji w tym samym bloku, na przykład w przypadku następującego kodu C:

if(a>b)
{
largest=a;  //here largest and count are integer variables
count+=1;
}

Można go napisać w Pythonie w jednej z dwóch form:

if a>b:   
    largest=a
    count=count+1

Lub

if a>b:    largest=a;count=count+1

W powyższym przykładzie możesz mieć dowolną liczbę instrukcji w ifbloku i można je oddzielić znakiem „;” zamiast.

Mam nadzieję, że nic nie jest tak proste, jak powyższe wyjaśnienie.

Mohd Asim
źródło
0

Dodając do ogromnej wiedzy, którą tutaj prezentujemy,
jest to odpowiedź związana z biblioteką matplotlib

import numpy as np
import matplotlib as plt
%matplotlib notebook
linear_data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
quadratic_data = linear_data**2
plt.figure()
xvals = range(len(linear_data))
plt.barh(xvals, linear_data, height = 0.3, color='b')
plt.barh(xvals, quadratic_data, height = 0.3, left=linear_data, color='r')

Jeśli nie podasz średnika na końcu kreski (poziomej kreski), wynikiem będzie wykres + adres funkcji. Ale jeśli użyjesz średników na końcu obu linii barh, to pokazuje tylko wykres i pomija dane wyjściowe dla adresu funkcji.

Coś takiego: Porównanie

Farhan Khan
źródło
3
Jest to specyficzne dla IPythona i nie ma zastosowania do standardowej REPL języka Python.
wjandrea
Myślę, że jest to wspaniały przykład, w którym sposób, w jaki autorzy języka sądzili, że wprowadzają prostotę, siłę i jednolitość, nie potrafił myśleć z wyprzedzeniem o problemach takich jak ten.
eSurfsnake