Sintaxa și semantica Python - Python syntax and semantics
Sintaxa de limbajul de programare Python este un set de reguli care stabilesc modul în care un program de Python va fi scrise și interpretate (atât de sistemul de execuție și de cititorii umani). Limbajul Python are multe asemănări cu Perl , C și Java . Cu toate acestea, există unele diferențe clare între limbi.
Filozofia proiectării
Python a fost conceput pentru a fi un limbaj foarte lizibil . Are un aspect vizual relativ neted și folosește frecvent cuvinte cheie în limba engleză acolo unde alte limbi folosesc punctuația . Python își propune să fie simplu și consecvent în proiectarea sintaxei sale, încapsulat în mantra „Ar trebui să existe una - și de preferință doar una - modalitate evidentă de a o face”, din Zen of Python .
Această mantră se opune în mod deliberat mantrei Perl și Ruby , „ există mai multe modalități de ao face ”.
Cuvinte cheie
Python are 35 de cuvinte cheie sau cuvinte rezervate ; nu pot fi folosite ca identificatori .
andasassertasyncawaitbreakclasscontinuedefdelelifelseexceptFalsefinallyforfromglobalifimportinislambdaNonenonlocalnotorpassraisereturnTruetrywhilewithyield
- Note
Indentare
Python folosește spațiul alb pentru a delimita blocurile de flux de control (urmând regula off-side ). Python împrumută această caracteristică de la predecesorul său ABC : în loc de punctuație sau cuvinte cheie, folosește indentare pentru a indica parcursul unui bloc .
În așa-numitele limbaje „în format liber” - care utilizează structura blocului derivată din ALGOL - blocurile de cod sunt setate cu paranteze ( { }) sau cuvinte cheie. În majoritatea convențiilor de codare pentru aceste limbaje, programatorii indentează codul în mod convențional într-un bloc, pentru a-l deosebi vizual de codul din jur.
Un recursive funcție de nume foo, care este trecut un singur parametru , xși dacă parametrul este 0 va apela o altă funcție numită barși în caz contrar se va apela baz, care trece x, și , de asemenea , se numesc recursiv, care trece x-1ca parametru, ar putea fi puse în aplicare ca acest lucru în Python :
def foo(x):
if x == 0:
bar()
else:
baz(x)
foo(x - 1)
și ar putea fi scris astfel în C cu stilul de indentare K&R :
void foo(int x)
{
if (x == 0) {
bar();
} else {
baz(x);
foo(x - 1);
}
}
Python impune o convenție pe care programatorii în limbaje stil ALGOL o urmează adesea.
Codul indentat incorect ar putea fi citit greșit de un cititor uman diferit decât ar fi interpretat de un compilator sau interpret. Acest exemplu ilustrează o eroare introdusă prin indentare incorectă:
def foo(x):
if x == 0:
bar()
else:
baz(x)
foo(x - 1)
Aici, spre deosebire de fooexemplul de mai sus , apelul funcției de foo(x - 1)pe ultima linie este indentat eronat pentru a fi în afara blocului if/ else. Acest lucru ar face ca acesta să fie întotdeauna executat, chiar și atunci când xeste 0, rezultând o recursivitate nesfârșită .
În timp ce atât spațiul, cât și caracterele tabului sunt acceptate ca forme de indentare și se pot utiliza orice multiple de spații, spațiile sunt recomandate și 4 spații (ca în acest articol) sunt recomandate și sunt de departe cele mai frecvent utilizate. Amestecarea spațiilor și a filelor pe linii consecutive în același fișier de cod sursă nu este permisă începând cu Python 3, deoarece se pot crea erori greu de văzut, deoarece multe instrumente nu disting vizual spațiile și filele.
Structuri de date
Deoarece Python este un limbaj tastat dinamic , valorile Python , nu variabile, poartă informații de tip. Acest lucru are implicații pentru multe aspecte ale modului în care funcționează limbajul.
Toate variabilele din Python conțin referințe la obiecte, iar aceste referințe sunt transmise funcțiilor; o funcție nu poate modifica valoarea referințelor variabile în funcția sa de apelare (dar vezi mai jos pentru excepții). Unii oameni (inclusiv Guido van Rossum însuși) au numit această schemă de trecere a parametrilor „apel prin referință obiect”. O referință de obiect înseamnă un nume, iar referința transmisă este un „alias”, adică o copie a referinței la același obiect, la fel ca în C / C ++ . Valoarea obiectului poate fi modificată în funcția apelată cu „alias”, de exemplu:
>>> alist = ['a', 'b', 'c']
>>> def my_func(al):
... al.append('x')
... print(al)
...
>>> my_func(alist)
['a', 'b', 'c', 'x']
>>> alist
['a', 'b', 'c', 'x']
Funcția a my_funcschimbat valoarea lui alistcu argumentul formal al, care este un alias al alist. Cu toate acestea, orice încercare de a opera aliasul în sine nu va avea niciun efect asupra obiectului original. În Python, numele accesibile non-cele mai interioare-locale și nedeclarate-globale sunt toate pseudonime.
Dintre limbile tastate dinamic, Python este verificat moderat. Conversia implicită este definită pentru tipurile numerice (precum și pentru booleeni ), deci se poate înmulți în mod valid un număr complex cu un număr întreg (de exemplu) fără distribuirea explicită. Cu toate acestea, nu există o conversie implicită între, de exemplu, numere și șiruri ; un șir este un argument nevalid pentru o funcție matematică care așteaptă un număr.
Tipuri de bază
Python are o gamă largă de tipuri de date de bază. Pe lângă aritmetica convențională cu număr întreg și virgulă mobilă , acceptă în mod transparent aritmetica de precizie arbitrară , numerele complexe și numerele zecimale .
Python acceptă o mare varietate de operații de șir. Șirurile din Python sunt imuabile , deci o operație de șir, cum ar fi o înlocuire a caracterelor , care în alte limbaje de programare ar putea modifica șirul în loc , returnează un șir nou în Python. Considerațiile privind performanța uneori impun utilizarea tehnicilor speciale în programe care modifică șirurile intens, cum ar fi unirea matricelor de caractere în șiruri numai după cum este necesar.
Tipuri de colecție
Unul dintre aspectele foarte utile ale Python este conceptul de tipuri de colecție (sau container ) . În general, o colecție este un obiect care conține alte obiecte într-un mod ușor de referințat sau indexat . Colecțiile vin în două forme de bază: secvențe și mapări .
Tipurile secvențiale ordonate sunt liste ( matrice dinamice ), tupluri și șiruri. Toate secvențele sunt indexate pozițional (de la 0 la lungime - 1 ) și toate șirurile, cu excepția șirurilor, pot conține orice tip de obiect, inclusiv mai multe tipuri în aceeași secvență. Atât șirurile, cât și tuplurile sunt imuabile, făcându-le candidate perfecte pentru cheile de dicționar (vezi mai jos). Listele, pe de altă parte, sunt modificabile; elementele pot fi inserate, șterse, modificate, adăugate sau sortate în loc .
Mappările, pe de altă parte, sunt tipuri (adesea neordonate) implementate sub formă de dicționare care „mapează” un set de chei imuabile la elementele corespunzătoare (la fel ca o funcție matematică). De exemplu, s-ar putea defini un dicționar cu un șir "toast"mapat la întreg 42sau invers. Cheile dintr-un dicționar trebuie să fie de un tip Python imuabil, cum ar fi un număr întreg sau un șir, deoarece sub capotă sunt implementate printr-o funcție hash . Acest lucru face timp de căutare mult mai rapid, dar nu necesită schimbarea cheilor.
Dicționarele sunt esențiale pentru componentele interne ale Python, deoarece se află la baza tuturor obiectelor și claselor: mapările dintre numele variabilelor (șiruri) și valorile la care denumesc numele sunt stocate ca dicționare (vezi Sistemul de obiecte ). Deoarece aceste dicționare sunt direct accesibile (prin __dict__atributul unui obiect ), metaprogramarea este un proces simplu și natural în Python.
Un tip de colecție set este o colecție neindexată, neordonată, care nu conține duplicate și implementează operații teoretice stabilite , cum ar fi unirea , intersecția , diferența , diferența simetrică și testarea subsetului . Există două tipuri de seturi: setși frozenset, singura diferență fiind că seteste mutabil și frozenseteste imuabil. Elementele dintr-un set trebuie să fie lavabile. Astfel, de exemplu, a frozensetpoate fi un element al unui regulat, în settimp ce opusul nu este adevărat.
Python oferă, de asemenea, abilități extinse de manipulare a colecțiilor, cum ar fi controlul încorporării încorporat și un protocol de iterație generic.
Sistem de obiecte
În Python, totul este un obiect, chiar și clase. Clasele, ca obiecte, au o clasă, cunoscută sub numele de metaclasă . Python acceptă, de asemenea, mai multe moșteniri și mixins .
Limbajul acceptă o introspecție extinsă de tipuri și clase. Tipurile pot fi citite și comparate - tipurile sunt instanțe de type. Atributele unui obiect pot fi extrase ca dicționar.
Operatorii pot fi supraîncărcați în Python definind funcții speciale de membru - de exemplu, definirea unei metode numite __add__într-o clasă permite utilizatorului să utilizeze +operatorul pe obiecte din acea clasă.
Litere
Siruri de caractere
Python are diverse tipuri de litere șir .
Litere de șir normal
Fie ghilimele simple, fie duble pot fi folosite pentru a cita siruri. Spre deosebire de limbajele shell Unix, limbile influențate de Perl sau Perl, cum ar fi Ruby sau Groovy , ghilimelele simple și ghilimelele duble funcționează identic, adică nu există interpolare de șiruri a expresiilor $ foo . Cu toate acestea, interpolare se poate face în diferite moduri: cu „f-șiruri” (de la Python 3.6), folosind formatmetoda sau vechiul operator de format % string.
De exemplu, declarația Perl:
print "I just printed $num pages to the printer $printer\n"
este echivalent cu oricare dintre aceste afirmații Python:
print(f"I just printed {num} pages to the printer {printer}")
print("I just printed {} pages to the printer {}".format(num, printer))
print("I just printed {0} pages to the printer {1}".format(num, printer))
print("I just printed {num} pages to the printer {printer}".format(num=num, printer=printer))
print("I just printed %s pages to the printer %s" % (num, printer))
print("I just printed %(num)s pages to the printer %(printer)s" % {"num": num, "printer": printer})
Litere de șiruri multiple
Există, de asemenea, șiruri cu mai multe linii, care încep și se termină cu o serie de trei ghilimele simple sau duble și funcționează ca documentele de aici din Perl și Ruby .
Un exemplu simplu cu interpolare variabilă (folosind formatmetoda) este:
print("""Dear {recipient},
I wish you to leave Sunnydale and never return.
Not Quite Love,
{sender}
""".format(sender="Buffy the Vampire Slayer", recipient="Spike"))
Corzi brute
În cele din urmă, toate tipurile de șir menționate anterior vin în soiuri " brute " (notate prin plasarea unui r literal înainte de citatul de deschidere), care nu fac interpolare inversă și, prin urmare, sunt foarte utile pentru expresiile regulate ; comparați „@ -citat” în C # . Șirurile brute au fost inițial incluse special pentru expresii regulate. Datorită limitării tokenizer-ului, șirurile brute pot să nu aibă o bară inversă. Crearea unui șir brut care deține o cale Windows care se termină cu o bară inversă necesită o varietate de soluții alternative (de obicei, folosind bare oblice înainte în loc de bare oblice inversă, deoarece Windows acceptă ambele).
Exemplele includ:
>>> # A Windows path, even raw strings cannot end in a backslash
>>> r"C:\Foo\Bar\Baz\"
File "<stdin>", line 1
r"C:\Foo\Bar\Baz\"
^
SyntaxError: EOL while scanning string literal
>>> dos_path = r"C:\Foo\Bar\Baz\ " # avoids the error by adding
>>> dos_path.rstrip() # and removing trailing space
'C:\\Foo\\Bar\\Baz\\'
>>> quoted_dos_path = r'"{}"'.format(dos_path)
>>> quoted_dos_path
'"C:\\Foo\\Bar\\Baz\\ "'
>>> # A regular expression matching a quoted string with possible backslash quoting
>>> re.match(r'"(([^"\\]|\\.)*)"', quoted_dos_path).group(1).rstrip()
'C:\\Foo\\Bar\\Baz\\'
>>> code = 'foo(2, bar)'
>>> # Reverse the arguments in a two-arg function call
>>> re.sub(r'\(([^,]*?),([^ ,]*?)\)', r'(\2, \1)', code)
'foo(2, bar)'
>>> # Note that this won't work if either argument has parens or commas in it.
Concatenarea literelor șirului adiacente
Literalele șirului (folosind convenții de citate diferite) care apar în mod contigu și separate doar prin spații albe (inclusiv linii noi), sunt permise și sunt agregate într-un singur șir mai lung. Prin urmare
title = "One Good Turn: " \
'A Natural History of the Screwdriver and the Screw'
este echivalent cu
title = "One Good Turn: A Natural History of the Screwdriver and the Screw"
Unicode
Din Python 3.0, setul de caractere implicit este UTF-8 atât pentru codul sursă, cât și pentru interpret. În UTF-8, șirurile Unicode sunt tratate ca șirurile de octeți tradiționali. Acest exemplu va funcționa:
s = "Γειά" # Hello in Greek
print(s)
Numere
Literali numerice în Python sunt de fel normale, de exemplu 0, -1, 3.4, 3.5e-8.
Python are numere întregi de lungime arbitrară și crește automat dimensiunea lor de stocare, după cum este necesar. Înainte de Python 3, existau două tipuri de numere întregi: numere întregi tradiționale cu mărime fixă și numere întregi „lungi” de mărime arbitrară. Conversia la numere întregi „lungi” a fost efectuată automat atunci când este necesar, și astfel programatorul nu trebuia de obicei să fie conștient de cele două tipuri integrale. În versiunile lingvistice mai noi, distincția a dispărut complet și toate numerele întregi se comportă ca numere întregi de lungime arbitrară.
Python acceptă numere normale în virgulă mobilă , care sunt create atunci când un punct este utilizat într-un literal (de ex. 1.1), Când un număr întreg și un număr în virgulă mobilă sunt utilizate într-o expresie sau ca urmare a unor operații matematice („divizare adevărată” prin /operatorul, sau exponentiala cu un exponent negativ).
Python acceptă, de asemenea, numere complexe în mod nativ. Numerele complexe sunt indicate cu sufixul Jsau j, de ex 3 + 4j.
Liste, tupluri, seturi, dicționare
Python are suport sintactic pentru crearea tipurilor de containere.
Listele (clasa list) sunt secvențe mutabile de articole de tipuri arbitrare și pot fi create fie cu sintaxa specială
a_list = [1, 2, 3, "a dog"]
sau folosind crearea obiectelor normale
a_second_list = list()
a_second_list.append(4)
a_second_list.append(5)
Tuplurile (clasa tuple) sunt secvențe imuabile de articole de tipuri arbitrare. Există, de asemenea, o sintaxă specială pentru a crea tupluri
a_tuple = 1, 2, 3, "four"
a_tuple = (1, 2, 3, "four")
Deși tuplurile sunt create prin separarea articolelor cu virgule, întregul construct este de obicei înfășurat în paranteze pentru a crește lizibilitatea. Un tuplu gol este notat cu ().
Seturile (clasa set) sunt containere care pot fi modificate cu articole hashable de tipuri arbitrare, fără duplicate. Articolele nu sunt comandate, dar seturile acceptă iterația asupra articolelor. Sintaxa pentru crearea setului folosește paranteze cretate
some_set = {0, (), False}
Seturile Python seamănă foarte mult cu seturile matematice și susțin operațiuni precum intersecția și unirea seturilor . Python oferă, de asemenea, o frozensetclasă pentru seturi imuabile, consultați Tipuri de colecție .
Dicționarele (clasa dict) sunt mapări mutabile care leagă cheile și valorile corespunzătoare. Python are o sintaxă specială pentru a crea dicționare ( {key: value})
a_dictionary = {"key 1": "value 1", 2: 3, 4: []}
Sintaxa dicționarului este similară cu sintaxa setată, diferența este prezența de două puncte. Gol literale {}rezultate în mai degrabă decât un dicționar gol un set gol, care este în schimb creat folosind constructorul non-literal: set().
Operatori
Aritmetic
Python include +, -, *, /( "diviziunea adevărată"), //( podea diviziune), %( modul ), și **( exponentiala operatori), cu lor obișnuită prioritate matematică .
În Python 3, x / yefectuează „diviziune adevărată”, ceea ce înseamnă că returnează întotdeauna un float, chiar dacă ambele xși ysunt numere întregi care se împart în mod egal.
>>> 4 / 2
2.0
și //efectuează împărțirea numărului întreg sau împărțirea etajului , returnând etajul coeficientului ca număr întreg.
În Python 2 (și în majoritatea celorlalte limbaje de programare), cu excepția cazului în care este solicitat în mod explicit, s-a x / yefectuat împărțirea întregului , returnând un float numai dacă oricare dintre intrări a fost un float. Cu toate acestea, deoarece Python este un limbaj tastat dinamic, nu a fost întotdeauna posibil să se spună ce operație a fost efectuată, ceea ce a dus adesea la erori subtile, determinând astfel introducerea //operatorului și schimbarea semanticii /operatorului în Python 3.
Operatori de comparație
Operatorii de comparație, de exemplu ==, !=, <, >, <=, >=, is, is not, inși not insunt utilizate pe tot felul de valori. Numerele, șirurile, secvențele și mapările pot fi comparate. În Python 3, tipurile disparate (cum ar fi a strși an int) nu au o ordonare relativă consistentă. Deși a fost posibil să se compare dacă un șir a fost mai mare decât sau mai puțin decât un număr întreg în Python 2, acesta a fost considerat o ciudățenie de proiectare istorică și a fost în cele din urmă eliminat în Python 3.
Expresiile de comparație înlănțuite, cum ar fi, a < b < cau aproximativ semnificația pe care o au în matematică, mai degrabă decât semnificația neobișnuită găsită în C și în limbi similare. Termenii sunt evaluați și comparați în ordine. Operația are semantică de scurtcircuit , ceea ce înseamnă că evaluarea este garantată pentru a se opri de îndată ce verdictul este clar: dacă a < beste fals, cnu este niciodată evaluat, deoarece expresia nu mai poate fi adevărată.
Pentru expresiile fără efecte secundare, a < b < ceste echivalent cu a < b and b < c. Cu toate acestea, există o diferență substanțială atunci când expresiile au efecte secundare. a < f(x) < bva evalua f(x)exact o dată, în timp ce o a < f(x) and f(x) < bva evalua de două ori dacă valoarea lui aeste mai mică decât f(x)și o dată altfel.
Operatori logici
În toate versiunile de Python, operatorii boolean trata valori zero sau valori goale , cum ar fi "", 0, None, 0.0, [], și {}ca fiind false, în timp ce , în general , tratarea non-goale, valorile zero ca fiind adevărate. Valorile booleene Trueși Falseau fost adăugate la limbaj în Python 2.2.1 ca constante (subclasate din 1și 0) și au fost modificate pentru a fi cuvinte cheie complete în Python 3. Operatorii de comparație binară precum ==și >returnează fie Truesau False.
Operatorii boolean andși orutilizați de evaluare minimă . De exemplu, y == 0 or x/y > 100nu va ridica niciodată o excepție divizare la zero. Acești operatori returnează valoarea ultimului operand evaluat, mai degrabă decât Truesau False. Astfel, expresia (4 and 5)evaluează 5și (4 or 5)evaluează la 4.
Programare funcțională
După cum sa menționat mai sus, un alt punct forte al Python este disponibilitatea unui stil de programare funcțional . După cum era de așteptat, acest lucru face ca lucrul cu listele și alte colecții să fie mult mai simplu.
Înțelegeri
O astfel de construcție este înțelegerea listei , care poate fi exprimată cu următorul format:
L = [mapping_expression for element in source_list if filter_expression]
Utilizarea înțelegerii listei pentru a calcula primele cinci puteri a două:
powers_of_two = [2**n for n in range(1, 6)]
Quicksort Algoritmul poate fi exprimat elegant (deși neeficient) folosind lista comprehensions:
def qsort(L):
if L == []:
return []
pivot = L[0]
return (qsort([x for x in L[1:] if x < pivot]) +
[pivot] +
qsort([x for x in L[1:] if x >= pivot]))
Python 2.7+ acceptă, de asemenea, înțelegeri de set și înțelegeri de dicționar.
Funcții de primă clasă
În Python, funcțiile sunt obiecte de primă clasă care pot fi create și transmise dinamic.
Suportul limitat al Python pentru funcții anonime este lambdaconstrucția. Un exemplu este funcția anonimă care pătrează intrarea sa, numită cu argumentul lui 5:
f = lambda x: x**2
f(5)
Lambdas se limitează la conținerea unei expresii mai degrabă decât a unor instrucțiuni , deși fluxul de control poate fi implementat mai puțin elegant în cadrul lambda utilizând scurtcircuitul și mai idiomatic cu expresii condiționale.
Închideri
Python a acceptat închiderile lexicale de la versiunea 2.2. Iată un exemplu de funcție care returnează o funcție care aproximează derivata funcției date:
def derivative(f, dx):
"""Return a function that approximates the derivative of f
using an interval of dx, which should be appropriately small.
"""
def function(x):
return (f(x + dx) - f(x)) / dx
return function
Totuși, sintaxa lui Python îi conduce uneori pe programatorii altor limbi să creadă că închiderile nu sunt acceptate. Domeniul de aplicare variabil în Python este implicit determinat de domeniul în care se atribuie o valoare variabilei, cu excepția cazului în care domeniul de aplicare este declarat în mod explicit cu globalsau nonlocal.
Rețineți că legarea unui nume la o anumită valoare nu poate fi modificată din interiorul funcției. Dat:
>>> def foo(a, b):
... print(f'a: {a}')
... print(f'b: {b}')
... def bar(c):
... b = c
... print(f'b*: {b}')
... bar(a)
... print(f'b: {b}')
...
>>> foo(1, 2)
a: 1
b: 2
b*: 1
b: 2
și puteți vedea că b, așa cum este vizibil din scopul închiderii, păstrează valoarea pe care a avut-o; legătura modificată a bfuncției interioare nu s-a propagat. Modalitatea de a rezolva acest lucru este de a utiliza o nonlocal bdeclarație în bar. În Python 2 (care lipsește nonlocal), soluția obișnuită este să folosiți o valoare mutabilă și să modificați acea valoare, nu legarea. De exemplu, o listă cu un singur element.
Generatoare
Introducute în Python 2.2 ca o caracteristică opțională și finalizate în versiunea 2.3, generatoarele sunt mecanismul Python pentru evaluarea leneșă a unei funcții care altfel ar returna o listă prohibitivă din punct de vedere spațial sau intensă din punct de vedere al calculului.
Acesta este un exemplu pentru a genera alene numerele prime:
from itertools import count
def generate_primes(stop_at=None):
primes = []
for n in count(start=2):
if stop_at is not None and n > stop_at:
return # raises the StopIteration exception
composite = False
for p in primes:
if not n % p:
composite = True
break
elif p ** 2 > n:
break
if not composite:
primes.append(n)
yield n
Când apelați această funcție, valoarea returnată poate fi repetată la fel ca o listă:
for i in generate_primes(100): # iterate over the primes between 0 and 100
print(i)
for i in generate_primes(): # iterate over ALL primes indefinitely
print(i)
Definiția unui generator apare identică cu cea a unei funcții, cu excepția cuvântului cheie care yieldeste utilizat în locul lui return. Cu toate acestea, un generator este un obiect cu stare persistentă, care poate intra și părăsi în mod repetat același scop. Un apel generator poate fi apoi utilizat în locul unei liste sau a unei alte structuri ale cărei elemente vor fi repetate. Ori de câte ori forbucla din exemplu necesită următorul articol, generatorul este apelat și produce următorul articol.
Generatoarele nu trebuie să fie infinite ca exemplul cu numărul prim de mai sus. Când un generator se termină, se ridică o excepție internă care indică oricărui context apelant că nu mai există valori. O forbuclă sau altă iterație se va termina apoi.
Expresii generatoare
Introducute în Python 2.4, expresiile generatoare sunt echivalentul leneș de evaluare a înțelegerilor listei. Folosind generatorul de numere prime furnizat în secțiunea de mai sus, am putea defini o colecție leneșă, dar nu destul de infinită.
from itertools import islice
primes_under_million = (i for i in generate_primes() if i < 1000000)
two_thousandth_prime = islice(primes_under_million, 1999, 2000).next()
Cea mai mare parte a memoriei și a timpului necesar pentru a genera atât de multe prime nu va fi folosită până când elementul necesar nu va fi accesat efectiv. Din păcate, nu puteți efectua indexarea și felierea simplă a generatoarelor, dar trebuie să utilizați modulul itertools sau să vă „rulați propriile” bucle. În schimb, o înțelegere a listei este echivalentă funcțional, dar este lacomă în efectuarea tuturor lucrărilor:
primes_under_million = [i for i in generate_primes(2000000) if i < 1000000]
two_thousandth_prime = primes_under_million[1999]
Înțelegerea listei va crea imediat o listă mare (cu 78498 de elemente, în exemplu, dar creând temporar o listă de numere prime sub două milioane), chiar dacă majoritatea elementelor nu sunt accesate niciodată. Înțelegerea generatorului este mai parsimonios.
Dicționar și set comprehensions
În timp ce listele și generatoarele au avut înțelegeri / expresii, în versiunile Python mai vechi de 2.7 celelalte tipuri de colecție încorporate Python (dicte și seturi) trebuiau să fie încurcate în utilizarea listelor sau generatoarelor:
>>> dict((n, n*n) for n in range(5))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Python 2.7 și 3.0 au unificat toate tipurile de colecție introducând dicționare și seturi de înțelegeri, similare cu înțelegerile de listă:
>>> [n*n for n in range(5)] # regular list comprehension
[0, 1, 4, 9, 16]
>>>
>>> {n*n for n in range(5)} # set comprehension
{0, 1, 4, 9, 16}
>>>
>>> {n: n*n for n in range(5)} # dict comprehension
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Obiecte
Python acceptă majoritatea tehnicilor de programare orientată pe obiecte (OOP). Permite polimorfismul , nu numai în cadrul unei ierarhii de clase, ci și prin tastarea rațelor . Orice obiect poate fi folosit pentru orice tip și va funcționa atâta timp cât are metodele și atributele adecvate. Și totul în Python este un obiect, inclusiv clase, funcții, numere și module. Python are, de asemenea, suport pentru metaclasele , un instrument avansat pentru îmbunătățirea funcționalității claselor. Bineînțeles, moștenirea , inclusiv moștenirea multiplă , este acceptată. Python are un suport foarte limitat pentru variabilele private care folosesc manglarea numelor, care este rareori folosită în practică, deoarece ascunderea informațiilor este văzută de unii ca fiind netiponică , în sensul că sugerează că clasa în cauză conține interne inestetice sau prost planificate. Sloganul „suntem toți utilizatori responsabili aici” este folosit pentru a descrie această atitudine.
Așa cum este adevărat pentru module, clasele din Python nu pun o barieră absolută între definiție și utilizator, ci se bazează mai degrabă pe politețea utilizatorului pentru a nu „pătrunde în definiție”.
- 9. Clase , Tutorial Python 2.6 (2013)
Doctrinele OOP, cum ar fi utilizarea metodelor de acces pentru a citi membrii datelor, nu sunt aplicate în Python. Așa cum Python oferă construcții de programare funcțională, dar nu încearcă să solicite transparență referențială , oferă un sistem de obiecte, dar nu cere comportament OOP . Mai mult, este întotdeauna posibilă redefinirea clasei folosind proprietăți (vezi Proprietăți ) astfel încât atunci când o anumită variabilă este setată sau recuperată în codul de apelare, aceasta invocă într-adevăr un apel funcțional, astfel încât spam.eggs = toasts-ar putea invoca cu adevărat spam.set_eggs(toast). Acest lucru anulează avantajul practic al funcțiilor de accesor și rămâne OOP deoarece proprietatea eggsdevine o parte legitimă a interfeței obiectului: nu trebuie să reflecte un detaliu de implementare.
În versiunea 2.2 a Python, au fost introduse clasele „în stil nou”. Cu clase de stil nou, obiectele și tipurile au fost unificate, permițând subclasificarea tipurilor. Chiar și tipuri complet noi pot fi definite, completate cu un comportament personalizat pentru operatorii infix. Acest lucru permite ca multe lucruri radicale să fie făcute sintactic în Python. O nouă metodă de rezolvare a ordinii pentru moștenirea multiplă a fost de asemenea adoptată cu Python 2.3. De asemenea, este posibil să rulați cod personalizat în timp ce accesați sau setați atribute, deși detaliile acestor tehnici au evoluat între versiunile Python.
Cu declarație
withDeclarația se ocupă de resurse, și permite utilizatorilor să lucreze cu protocolul de context Manager. O funcție ( __enter__()) este apelată la introducerea scopului și alta ( __exit__()) la ieșire. Acest lucru împiedică uitarea de a elibera resursa și, de asemenea, gestionează situații mai complicate, cum ar fi eliberarea resursei atunci când apare o excepție în timp ce este utilizată. Managerii de context sunt adesea folosiți cu fișiere, conexiuni la baze de date, cazuri de testare etc.
Proprietăți
Proprietățile permit invocarea metodelor special definite pe o instanță de obiect utilizând aceeași sintaxă ca și cea utilizată pentru accesul la atribute. Un exemplu de clasă care definește unele proprietăți este:
class MyClass:
def __init__(self):
self._a = None
@property
def a(self):
return self._a
@a.setter # makes the property writable
def a(self, value):
self._a = value
Descriptori
O clasă care definește una sau mai multe dintre cele trei metode speciale __get__(self, instance, owner), __set__(self, instance, value), __delete__(self, instance)poate fi folosit ca un descriptor. Crearea unei instanțe a unui descriptor ca membru al clasei unei clase a doua face ca instanța să fie o proprietate a clasei a doua.
Metode de clasă și statice
Python permite crearea de metode de clasă și metode statice prin utilizarea decoratorilor@classmethod și . Primul argument pentru o metodă de clasă este obiectul de clasă în loc de auto-referință la instanță. O metodă statică nu are un prim argument special. Nici instanța, nici obiectul clasei nu sunt transmise unei metode statice.
@staticmethod
Excepții
Python acceptă (și folosește pe scară largă) gestionarea excepțiilor ca mijloc de testare a condițiilor de eroare și a altor evenimente „excepționale” dintr-un program. Într-adevăr, este chiar posibil să surprindem excepția cauzată de o eroare de sintaxă .
Stilul Python solicită utilizarea excepțiilor ori de câte ori poate apărea o condiție de eroare. În loc să testați accesul la un fișier sau la o resursă înainte de a-l utiliza efectiv, este obișnuit în Python să mergeți mai departe și să încercați să-l utilizați, prinzând excepția dacă accesul este respins.
Excepțiile pot fi, de asemenea, utilizate ca un mijloc mai general de transfer non-local de control, chiar și atunci când nu se pune problema unei erori. De exemplu, software-ul Mailman listă de corespondență, scris în Python, folosește excepții pentru a ieși din logica de gestionare a mesajelor profund imbricată atunci când s-a luat decizia de a respinge un mesaj sau de a-l reține pentru aprobarea moderatorului.
Excepțiile sunt adesea folosite ca alternativă la if-blocare, în special în situații filetate . Un motto invocat frecvent este EAFP, sau „Este mai ușor să ceri iertare decât permisiunea”, care este atribuit lui Grace Hopper . Alternativa, cunoscută sub numele de LBYL sau „Look Before You Leap”, testează în mod explicit pentru condițiile anterioare.
În acest prim exemplu de cod, urmând abordarea LBYL, există o verificare explicită pentru atribut înainte de acces:
if hasattr(spam, 'eggs'):
ham = spam.eggs
else:
handle_missing_attr()
Acest al doilea eșantion urmează paradigma EAFP:
try:
ham = spam.eggs
except AttributeError:
handle_missing_attr()
Aceste două eșantioane de coduri au același efect, deși vor exista diferențe de performanță. Când spamare atributul eggs, eșantionul EAFP va rula mai repede. Când spamnu are atributul eggs(cazul „excepțional”), eșantionul EAFP va rula mai lent. Profilatorul Python poate fi utilizat în cazuri specifice pentru a determina caracteristicile de performanță. Dacă cazurile excepționale sunt rare, atunci versiunea EAFP va avea o performanță medie superioară celei alternative. În plus, evită întreaga clasă de vulnerabilități la momentul verificării până la timpul de utilizare (TOCTTOU), alte condiții de rasă și este compatibil cu tastarea rațelor . Un dezavantaj al EAFP este că poate fi utilizat numai cu declarații; o excepție nu poate fi surprinsă într-o expresie generatoare, înțelegerea listei sau funcția lambda.
Comentarii și șiruri de documente
Python are două moduri de a adnota codul Python. Una este folosirea comentariilor pentru a indica ce face o parte a codului. Comentariile pe o singură linie încep cu caracterul hash ( #) și continuă până la sfârșitul liniei. Comentariile care se întind pe mai mult de o linie sunt realizate prin inserarea unui șir cu mai multe linii (cu """sau '''ca delimitator la fiecare capăt) care nu este utilizat în atribuire sau evaluat în alt mod, dar se află între alte instrucțiuni.
Comentează o bucată de cod:
import sys
def getline():
return sys.stdin.readline() # Get one line and return it
Comentează o bucată de cod cu mai multe linii:
def getline():
return sys.stdin.readline() """this function
gets one line
and returns it"""
Docstrings (șiruri de documentare), adică șiruri care sunt situate singure fără atribuire ca prima linie indentată dintr-un modul, clasă, metodă sau funcție, își setează automat conținutul ca un atribut numit __doc__, care este destinat să stocheze o descriere care poate fi citită de om a scopului, comportamentului și utilizării obiectului. Funcția încorporată helpîși generează ieșirea pe baza __doc__atributelor. Astfel de șiruri pot fi delimitate cu "sau 'pentru șiruri cu o singură linie sau pot cuprinde mai multe linii dacă sunt delimitate cu una """sau '''care este notația Python pentru specificarea șirurilor cu mai multe linii. Cu toate acestea, ghidul de stil pentru limbă specifică faptul că ghilimelele triple duble ( """) sunt preferate atât pentru șiruri de documente simple, cât și pentru mai multe linii.
Șir de documente cu o singură linie:
def getline():
"""Get one line from stdin and return it."""
return sys.stdin.readline()
Șir de documente cu mai multe linii:
def getline():
"""Get one line
from stdin
and return it.
"""
return sys.stdin.readline()
Docstring-urile pot fi la fel de mari pe cât dorește programatorul și pot conține pauze de linie . Spre deosebire de comentarii, șirurile de documente sunt ele însele obiecte Python și fac parte din codul interpretat pe care îl rulează Python. Asta înseamnă că un program în execuție își poate recupera propriile docstrings și poate manipula acele informații, dar utilizarea normală este de a oferi altor programatori informații despre cum să invoce obiectul documentat în docstring.
Există instrumente disponibile care pot extrage șirurile de documente din codul Python și pot genera documentație. Documentația Docstring poate fi accesată și din interpretul cu help()funcția sau din shell cu comanda pydocpydoc .
Modulul doctest standard utilizează interacțiuni copiate din sesiunile de shell Python în docstrings pentru a crea teste, în timp ce modulul docopt le folosește pentru a defini opțiunile din linia de comandă.
Adnotări de funcții
Adnotările de funcții (indicii de tip) sunt definite în PEP 3107. Permit atașarea de date la argumentele și returnarea unei funcții. Comportamentul adnotărilor nu este definit de limbă și este lăsat în sarcina cadrelor terților. De exemplu, o bibliotecă ar putea fi scrisă pentru a gestiona tastarea statică:
def haul(item: Haulable, *vargs: PackAnimal) -> Distance
Decoratori
Un decorator este orice obiect Python apelabil care este folosit pentru a modifica o funcție, o metodă sau o definiție a clasei. Un decorator primește obiectul original care este definit și returnează un obiect modificat, care este apoi legat de numele din definiție. Decoratorii Python au fost inspirați parțial de adnotări Java și au o sintaxă similară; sintaxa decoratorului este zahăr sintactic pur , folosind @ca cuvânt cheie:
@viking_chorus
def menu_item():
print("spam")
este echivalent cu
def menu_item():
print("spam")
menu_item = viking_chorus(menu_item)
Decoratorii sunt o formă de metaprogramare ; ele sporesc acțiunea funcției sau metodei pe care o decorează. De exemplu, în eșantionul de mai jos, viking_choruspoate menu_itemfi executat de 8 ori (vezi Schița spam ) pentru fiecare dată când este numit:
def viking_chorus(myfunc):
def inner_func(*args, **kwargs):
for i in range(8):
myfunc(*args, **kwargs)
return inner_func
Utilizările canonice ale decoratorilor de funcții sunt pentru crearea de metode de clasă sau metode statice , adăugarea atributelor funcției, urmărirea , setarea pre- și postcondiții și sincronizare , dar pot fi utilizate pentru mult mai multe, inclusiv eliminarea recursivității cozii , memoizarea și chiar îmbunătățirea scrierii altora decoratori.
Decoratorii pot fi înlănțuiți plasând mai multe pe liniile adiacente:
@invincible
@favourite_colour("Blue")
def black_knight():
pass
este echivalent cu
def black_knight():
pass
black_knight = invincible(favourite_colour("Blue")(black_knight))
sau, folosind variabile intermediare
def black_knight():
pass
blue_decorator = favourite_colour("Blue")
decorated_by_blue = blue_decorator(black_knight)
black_knight = invincible(decorated_by_blue)
În exemplul de mai sus, fabrica defavourite_colour decoratori ia un argument. Fabricile de decoratori trebuie să returneze un decorator, care este apoi chemat cu obiectul care urmează să fie decorat ca argument:
def favourite_colour(colour):
def decorator(func):
def wrapper():
print(colour)
func()
return wrapper
return decorator
Acest lucru ar decora apoi black_knightfuncția astfel încât culoarea "Blue",, să fie tipărită înainte de black_knightfuncționarea funcției. Închiderea asigură faptul că argumentul culorilor este accesibil funcției cele mai interioare de înfășurare chiar și atunci când este returnat și iese din scop, ceea ce permite decoratorilor să lucreze.
În ciuda numelui, decoratorii Python nu sunt o implementare a modelului decorator . Modelul decorator este un model de proiectare utilizat în limbaje de programare orientate obiect, tipizate static, pentru a permite adăugarea funcționalității obiectelor în timpul rulării; Decoratorii Python adaugă funcționalitate funcțiilor și metodelor la momentul definirii și, prin urmare, sunt o construcție de nivel superior decât clasele de modele de decoratori. Modelul decorator în sine este implementabil în mod trivial în Python, deoarece limbajul este tipat de rață și, prin urmare, nu este de obicei considerat ca atare.
Ouă de Paște
Utilizatorii de limbaje între paranteze , cum ar fi C sau Java , uneori așteaptă sau doresc ca Python să urmeze o convenție de delimitare a blocurilor. Sintaxa blocului delimitat de paranteze a fost solicitată în mod repetat și respinsă în mod constant de către dezvoltatorii de bază. Interpretul Python conține un ou de Paște care rezumă sentimentele dezvoltatorilor săi cu privire la această problemă. Codul from __future__ import bracesridică excepția SyntaxError: not a chance. __future__Modulul este utilizat în mod normal pentru a oferi caracteristici de la versiunile viitoare ale Python.
Un alt mesaj ascuns, Zen of Python (un rezumat al filozofiei de proiectare Python ), este afișat atunci când se încearcă import this.
Mesajul Hello world!este tipărit atunci când import __hello__este utilizată declarația de import . În Python 2.7, în loc să Hello world!se imprime Hello world....
Importarea antigravitymodulului deschide un browser web pentru xkcd comic 353 care descrie o utilizare fictivă plină de umor pentru un astfel de modul, menită să demonstreze ușurința cu care modulele Python permit funcționalități suplimentare. În Python 3, acest modul conține, de asemenea, o implementare a algoritmului „geohash”, o referință la xkcd comic 426 .
Referințe
linkuri externe
- Tutorial Python scris de autorul Python, Guido van Rossum.