vineri, 19 ianuarie 2018

Python un limbaj accesibil


Python este un limbaj de programare general, versatil și puternic. Este o limbă maternă excelentă, deoarece este concisă și ușor de citit. Orice vrei să faci, Python o poate face. De la dezvoltarea web la învățarea automată până la știința datelor

Structuri de date Acest capitol descrie unele lucruri pe care le-ați învățat deja în detaliu și adaugă și câteva lucruri noi.Mai multe despre Liste 

Tipul de date listă are mai multe metode. Iată toate metodele de listă a obiectelor:
listă. adăugați )
Adăugați un element la sfârșitul listei. Echivalent cu o [len (a):] [x] .
listă. extinde )
Extindeți lista adăugând toate elementele din lista dată. Echivalent cu un [len (a):] L .
listă. inserați i , )
Introduceți un element într-o poziție dată. Primul argument este indexul elementului înaintea căruia se introduce, astfel încât a.insert (0, x) se inserează în partea din față a listei și a.insert (len (a), x) este echivalent cu a.append ( x) .
listă. eliminați )
Eliminați primul element din lista a cărei valoare este x . Este o eroare dacă nu există un astfel de element.
listă. pop )
Scoateți articolul din poziția dată din listă și returnați-l. Dacă nu este specificat niciun index, a.pop () elimină și returnează ultimul element din listă. (Parantezele pătrate în jurul valorii de i în semnătura metodei indică faptul că parametrul este opțional, nu că trebuie să introduceți paranteze pătrate în acea poziție. Veți vedea această notație frecvent în Python Library Reference.)
listă. clar )
Eliminați toate elementele din listă. Echivalent cu del a [:] .
listă. index )
Returnați indexul în lista primului element a cărui valoare este x . Este o eroare dacă nu există un astfel de element.
listă. număr )
Reveniți de câte ori x apare în listă.
listă. sort )
Sortați elementele din listă în loc.
listă. invers )
Inversați elementele din listă în loc.
listă. copie )
Returnați o copie superioară a listei. Echivalent cu un [:] .
Un exemplu care utilizează majoritatea metodelor listă:
>>>
>>> a  =  [ 66,25 ,  333 ,  333 ,  1 ,  1234,5 ] 
>>> print ( a . Conta ( 333 ),  un . Conta ( 66,25 ),  un . Număr ( 'x' )) 
2 1 0 
>>> a . inserați ( 2 ,  - 1 ) 
>>> a . adăuga ( 333 ) 
>>> a
[66.25, 333, -1, 333, 1, 1234.5, 333] 
>>> a . index ( 333 ) 
1 
>>> a . eliminați ( 333 ) 
>>> a 
[66.25, -1, 333, 1, 1234.5, 333] 
>>> a . inversă () 
>>> a 
[333, 1234.5, 1, 333, -1, 66.25] 
>>> a . sortare () 
>>> a 
[-1, 1, 66.25, 333, 333, 1234.5]
S-ar putea să fi observat că metode cum ar fi inserarea , ștergerea sau sortarea care modifică lista nu au nici o valoare returnată imprimată - acestea returnează Niciuna . [1] Acesta este un principiu de proiectare pentru toate structurile de date mutabile din Python.

 Ce să mai citim?


5.1.1. Utilizarea listelor ca stive 

Metodele din listă fac foarte ușor utilizarea unei liste ca stiva, unde ultimul element adăugat este primul element preluat ("last-in, first-out"). Pentru a adăuga un element în partea de sus a stivei, utilizați atașați () . Pentru a prelua un element din partea de sus a stivei, folosiți pop () fără un index explicit. De exemplu:
>>>
>>> stivă  =  [ 3 ,  4 ,  5 ] 
>>> stivă . adăugați ( 6 ) 
>>> stivă . adăugați ( 7 ) 
>>> stivă 
[3, 4, 5, 6, 7] 
>>> stivă . pop () 
7 
>>> stivă 
[3, 4, 5, 6] 
>>> stivă . pop () 
6 
>>> stivă . pop () 
5 
>>> stivă 
[3, 4]

5.1.2. Utilizarea listelor ca Cozile 


Este, de asemenea, posibilă utilizarea unei liste ca o coadă, în care primul element adăugat este primul element preluat ("first-in, first-out"); totuși, listele nu sunt eficiente în acest scop. În timp ce apendicele și pop-urile de la sfârșitul listei sunt rapide, inserarea sau ștampila de la începutul unei liste este lentă (deoarece toate celelalte elemente trebuie să fie deplasate de una).
Pentru a pune în aplicare o coadă, utilizați collections.deque care a fost proiectat pentru a avea rapide apendice și apare de la ambele capete. De exemplu:
>>>
>>> din  colecții  import  deque 
>>> queue  =  deque ( "Eric" ,  "John" ,  "Michael" )) 
>>> coadă . append ( "Terry" )            # Terry sosește 
>>> coadă . append ( "Graham" )           # Graham sosește 
>>> coadă . popleft ()                  # Primul care ajunge acum lasă 
"Eric" 
>>> coadă .                 
'John' 
>>> coadă                            # 
Coada rămasă în ordinea sosirii deque (['Michael', 'Terry', 'Graham'])

5.1.3. Lista înțelegerilor 


Lista de înțelegeri oferă o modalitate concisă de a crea liste. Aplicațiile comune sunt de a face noi liste în care fiecare element este rezultatul unor operații aplicate fiecărui membru al unei alte secvențe sau iterabil sau pentru a crea o subsecventa a acelor elemente care satisfac o anumită condiție.
De exemplu, presupunem că vrem să creăm o listă de pătrate, cum ar fi:
>>>
>>> pătrate  =  [] 
>>> pentru  x  în  intervalul ( 10 ): 
...     pătrate . adăugați ( x ** 2 ) 
... 
>>> pătrate 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Putem obtine acelasi rezultat cu:
pătrate  =  [ x ** 2  pentru  x  în  intervalul ( 10 )]
Aceasta este, de asemenea, echivalentă cu pătratele listă (hartă (lambda x: x ** 2,interval (10))) , dar este mai concisă și mai lizibilă.
O înțelegere a listei constă din paranteze care conțin o expresie urmată de o clauză pentru , apoi de zero sau mai mult pentru sau în cazul clauzelor. Rezultatul va fi o nouă listă care rezultă din evaluarea expresiei în contextul clauzelor for și if care o urmează. De exemplu, această listcomp combină elementele a două liste dacă nu sunt egale:
>>>
>>> [( x ,  y )  pentru  x  în  [ 1 , 2 , 3 ]  pentru  y  în  [ 3 , 1 , 4 ]  dacă  x  ! =  Y ] 
[(1, 3), (1, 4), (2 , 3), (2, 1), (2, 4), (3, 1), (3, 4)]
și este echivalent cu:
>>>
>>> fag  =  [] 
>>> pentru  x  în  [ 1 , 2 , 3 ]: 
...     pentru  y  în  [ 3 , 1 , 4 ]: 
...         dacă  x  ! =  y : 
...             piepteni . atașa (( x ,  y )) 
... 
>>> piepteni 
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1 ), (3, 4)]
Rețineți cum ordinea instrucțiunilor for și if este aceeași în ambele aceste fragmente.
Dacă expresia este o tuplă (de exemplu, (x, y) din exemplul anterior), trebuie să fie paranteză.
>>>
>>> vec  =  [ - 4 ,  - 2 ,  0 ,  2 ,  4 ] 
>>> # a crea o nouă listă cu valorile dublate 
>>> [ x * 2  pentru  x  în  vec ] 
[-8, -4, 0 , 4, 8] 
>>> # filtrați lista pentru a exclude numerele negative 
>>> [ x  pentru  x  în  vec  dacă  x  > =  0 ] 
[0, 2, 4] 
>>> # aplică o funcție la toate elementele 
> >>[abs ( x )  pentru  x  în  vec ] 
[4, 2, 0, 2, 4] 
>>> # apela o metodă pe fiecare element 
>>> freshfruit  =  [ 'banana' ,  'loganberry' ,  'fructul pasiunii' ] 
> >> [ arma . benzi ()  pentru  arme  în  freshfruit ] 
[ 'banana', 'loganberry', 'fructul pasiunii'] 
>>> # a crea o listă de 2-tuple ca (număr, pătrat) 
>>> [( x ,  pentru  x  în  interval ( 6 )] 
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] 
>>> # tensiunea trebuie să fie parantezată, în caz contrar apare o eroare 
>>> [ x ,  x ** 2  pentru  x  în  intervalul ( 6 )] 
  Fișierul "<stdin>", rândul 1, în? 
    [x, x ** 2 pentru x în intervalul (6)] 
               ^ 
SyntaxError: sintaxa nevalidă 
>>> # aplatizarea unei liste folosind o listă compusă cu două 'pentru' 
>>> vec  =  [[ 1 , 2 , 3 ] [ 4 , 5 , 6 ],  [ 7 , 8 , 9 ]] 
>>> [ num  pentru  elem  în  vec  pentru  num  în  elem ] 
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Lista comprehensions poate conține expresii complexe și funcții imbricate:
>>>
>>> din  importul de matematică  pi >>> [ str ( rotund ( pi , i )) pentru i în intervalul ( 1 , 6 )] ['3.1', '3.14', '3.142', '3.1416' ] 
      

5.1.4. Înțelegeri ale listei încorporate 

Expresia inițială într-o înțelegere a listei poate fi orice expresie arbitrară, incluzând o altă înțelegere a listei.
Luați în considerare următorul exemplu de matrice 3x4 implementată ca o listă cu 3 liste de lungime 4:
>>>
>>> matrice  =  [ 
...     [ 1 ,  2 ,  3 ,  4 ], 
...     [ 5 ,  6 ,  7 ,  8 ], 
...     [ 9 ,  10 ,  11 ,  12 ], 
... ]
Următoarea listă de înțelegere va transpune rândurile și coloanele:
>>>
>>> [[ rând [ i ]  pentru  rândul  în  matrice ]  pentru  i  în  intervalul ( 4 )] 
[[1, 5, 9], [ 8, 12]]
Așa cum am văzut în secțiunea anterioară, lista listată imbricată este evaluată în contextul pentrucare o urmează, deci acest exemplu este echivalent cu:
>>>
>>> transpus  =  [] 
>>> pentru  i  în  intervalul ( 4 ): 
...     transpus . adăugați ([ rând [ i ]  pentru  rând  în  matrice ]) 
... 
>>> transpuse 
[[1, 5, 9], [2, 6, 10], [ 12]]
care, la rândul său, este la fel ca:
>>>
>>> transpus  =  [] 
>>> pentru  i  în  raza de acțiune ( 4 ): 
...     # Următoarele 3 rânduri implementează lista imbricată 
...     transposed_row  =  [] 
...     pentru  rândul  în  matrice : 
...         transposed_row . adăugați ( rând [ i ]) 
...     transpus . adăugați ( transposed_row ) 
... 
>>> transpus 
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4,8,12]]
În lumea reală, ar trebui să preferați funcțiile încorporate în declarațiile de flux complexe. Funcția zip () ar face o treabă excelentă pentru acest caz de utilizare:
>>>
>>> lista ( zip ( * matrix )) 
[(1, 5, 9), (2, 6, 10), (3, 7, 11)
Consultați Dezarhivarea listelor de argumente pentru detalii despre asterisc în acest rând.

5.2. Del Declarația 


Există o modalitate de a elimina un element dintr-o listă în locul indexului său, în locul valorii sale: instrucțiunea del . Aceasta diferă de metoda pop () care returnează o valoare. Instrucțiunea delpoate fi de asemenea folosită pentru a elimina felii dintr-o listă sau pentru a șterge întreaga listă (ceea ce am făcut mai devreme prin alocarea unei liste goale la felie). De exemplu:
>>>
>>> a  =  [ - 1 ,  1 ,  66.25 ,  333 ,  333 ,  1234,5 ] 
>>> del  a [ 0 ] 
>>> a 
[1, 66.25, 333, 333, 1234,5] 
>>> del  a [ 2 : 4 ] 
>>> a 
[1, 66.25, 1234.5] 
>>> del  a [:] 
>>> a 
[]
del poate fi, de asemenea, utilizat pentru a șterge variabilele întregi:
>>>
>>> del  a
Referindu-se la denumirea de mai jos este o eroare (cel puțin până când îi este atribuită o altă valoare). Vom găsi alte utilizări pentru del mai târziu.

5.3. Tupele și secvențe 


Am văzut că listele și șirurile au multe proprietăți comune, cum ar fi operațiile de indexare și de tăiere. Acestea sunt două exemple de tipuri de date de secvență (vedeți Tipuri de secvențe - listă, tuplă, interval ). Din moment ce Python este un limbaj în evoluție, pot fi adăugate alte tipuri de date secvențiale. Există, de asemenea, un alt tip de date standard de secvență: tupla .
O trupă constă dintr-un număr de valori separate prin virgule, de exemplu:
>>>
>>> t  =  12345 ,  54321 ,  "salut!" 
>>> t [ 0 ] 
12345 
>>> t 
(12345, 54321, 'alo!') 
>>> # Tuples poate fi imbricate: 
... u  =  t ,  ( 1 ,  2 ,  3 ,  4 ,  5 ) 
> >> u 
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) 
>>> # Tuples sunt imuabile: 
... t [ 0 ]  =  88888
Traceback (cel mai recent apel ultima): 
  Fișier "<stdin>" , linia 1 , în <modul> 
TypeError : 'tuplu' obiect nu are suport pentru atribuirea element 
>>> # dar ele pot conține obiecte modificabile: 
... v  =  ( [ 1 ,  2 ,  3 ],  [ 3 ,  2 ,  1 ]) 
>>> v 
([1, 2, 3], [3, 2, 1]
După cum vedeți, pe tuplele de ieșire sunt întotdeauna închise în paranteze, astfel că nopțile imbricate sunt interpretate corect; ele pot fi introduse cu sau fără paranteze înconjurătoare, deși adesea paranteze sunt necesare oricum (dacă tuplul face parte dintr-o expresie mai mare). Nu este posibilă alocarea elementelor individuale ale unei tuple, însă este posibil să se creeze tupluri care conțin obiecte mutabile, cum ar fi liste.
Deși tuplele pot părea similare cu listele, ele sunt adesea folosite în situații diferite și în scopuri diferite. Tupele sunt imuabile și conțin, de obicei, o secvență eterogenă de elemente care sunt accesate prin despachetare (a se vedea mai târziu în această secțiune) sau indexare (sau chiar prin atribut în cazul numerelor ). Listele sunt mutabile , iar elementele lor sunt, de obicei, omogene și sunt accesate prin iterarea în listă.
O problemă specială este construirea de tupluri care conțin 0 sau 1 elemente: sintaxa are unele ciudățenii suplimentare pentru a le acomoda. Gândurile goale sunt construite de o pereche goală de paranteze; un tuplu cu un element este construit urmând o valoare cu o virgulă (nu este suficient să închideți o singură valoare în paranteze). Urât, dar eficace. De exemplu:
>>>
>>> empty  =  () 
>>> singleton  =  'hello' ,     # <- virgula cu note în urmă 
>>> len ( gol ) 
0 
>>> len ( singleton ) 
1 
>>> singleton 
('hello',)
Declarația 12345, 54321, "salut!" este un exemplu de ambalare în tuple : valorile 12345 , 54321 și "salut!" sunt ambalate împreună într-o tuplă. Este posibilă și operarea inversă:
>>>
>>> x ,  y ,  z  =  t
Aceasta se numește, suficient de adecvat, despachetarea succesivă și funcționează pentru orice secvență din partea dreaptă. Descărcarea secvențelor necesită existența a numeroase variabile pe partea stângă a semnalului egal, deoarece există elemente în secvență. Rețineți că atribuirea mai multor este într-adevăr doar o combinație de împachetare tuplă și despachetare succesivă.

5.4. Seturi 


Python include, de asemenea, un tip de date pentru seturi . Un set este o colecție neordonată fără elemente duplicate. Utilizările de bază includ testarea membrilor și eliminarea intrărilor duplicate. Setarea obiectelor suportă și operații matematice cum ar fi unirea, intersecția, diferența și diferența simetrică.
Comenzile curry sau funcția set () pot fi folosite pentru a crea seturi. Notă: pentru a crea un set gol trebuie să utilizați set () , nu {} ; acesta din urmă creează un dicționar gol, o structură de date pe care o discutăm în secțiunea următoare.
Iată o scurtă demonstrație:
>>>
>>> coș  =  { 'apple' ,  'orange' ,  'apple' ,  'pear' ,  'orange' ,  'banana' } 
>>> print ( coș )                       # arată că duplicatele au fost eliminate 
{ banana "," pere "," mere "} 
>>> " portocaliu "  în  coș                  # rapid de testare a calității de membru 
Adevărat 
>>> 'crabgrass'  în  coș 
Fals

>>> # set operații pe Demonstrați scrisori unice de la două cuvinte 
... 
>>> un  =  set ( 'Abracadabra' ) 
>>> b  =  set ( 'alacazam' ) 
>>> un                                   scrisori # unic într - un 
{ 'o ',' r ',' b ',' c ',' d '} 
>>> a  -  b                               # litere într-un, dar nu în b 
{' r ',' d ',' b '} 
>>> a  |  b "                               litere în a sau b 
{'a', 'c', 'r', 'd', 'b', 'm', '
                                

a  ^  b                               # litere în a sau b, dar nu ambele 
{'r', 'd', 'b', 'm', 'z', 'l'}
În mod similar cu înțelegerile din listă , sunt de asemenea acceptate înțelegeri setate:
>>>
>>> a  =  { x  pentru  x  în  'abracadabra'  dacă  x  nu este  în  'abc' ) 
>>> a 
{'r', 'd'}

5.5. Dicționare 


Un alt tip de date util construit în Python este dicționarul (consultați Tipuri de cartografiere - dict ). Dicționarele sunt uneori găsite în alte limbi ca "amintiri asociative" sau "matrice asociative". Spre deosebire de secvențe, care sunt indexate printr-o serie de numere, dicționarele sunt indexate prin chei , care pot fi orice tip imuabil; șirurile și numerele pot fi întotdeauna chei. Tupele pot fi folosite ca chei dacă conțin numai șiruri, numere sau tuple; dacă o tuplă conține un obiect mutabil, direct sau indirect, nu poate fi folosit ca o cheie. Nu puteți utiliza listele ca chei, deoarece listele pot fi modificate în loc utilizând asignări index, alocări slice sau metode cum ar fi append () și extend () .
Cel mai bine este să gândiți un dicționar ca un set neordonat de perechi de chei: valoare , cu cerința că cheile sunt unice (într-un singur dicționar). O pereche de bretele creează un dicționar gol: {} . Plasarea unei liste separate de virgulă a perechilor de chei: valoare în cadrul brațelor adaugă cheia inițială: perechi de valori în dicționar; acesta este și modul în care sunt scrise dictionarele de ieșire.
Principalele operații dintr-un dicționar sunt stocarea unei valori cu unele chei și extragerea valorii date de tastă. Este, de asemenea, posibil să ștergeți o pereche cheie: valoare cu del . Dacă stocați utilizând o cheie deja utilizată, vechea valoare asociată acelei chei este uitată. Este o eroare să extrageți o valoare utilizând o cheie inexistentă.
Efectuarea unei liste (d.keys ()) într-un dicționar returnează o listă a tuturor cheilor folosite în dicționar, în ordine arbitrară (dacă doriți să fie sortată, utilizați în schimb sortate (d.keys () ). [2]Pentru a verifica dacă o singură tastă este în dicționar, utilizați cuvântul cheie în .
Iată un mic exemplu folosind un dicționar:
>>>
>>> tel  =  { 'jack' :  4098 ,  'sape' :  4139 ) 
>>> tel [ 'guido' ]  =  4127 
>>> tel 
{'sape': 4139, 'guido' 4098} 
>>> tel [ 'jack' ] 
4098 
>>> del  tel [ 'SAPE' ] 
>>> tel [ 'Irv' ]  =  4127 
>>> tel 
{ 'guido': 4127, 'Irv': 4127,'jack': 4098} 
>>> lista ( tel .chei ()) 
[ 'Irv', 'Guido', 'jack'] 
>>> sortate ( tel . chei ()) 
[ 'guido', 'Irv', 'jack'] 
>>> 'guido'  in  tel 
Adevărat 
>>> "Jack"  nu este  în  tel 
Fals
Constructorul dict () construiește dicționare direct din secvențe de perechi cheie-valoare:
>>>
>>> dict ( ' ( ' sape ' ,  4139 ),  ( ' guido ' ,  4127 ),  ( ' jack ' ,  4098 )]) 
{sape' 4139, jack: 4098, guido:
În plus, înțelegerile dict pot fi folosite pentru a crea dicționare din expresii cheie și valori arbitrare:
>>>
>>> { x :  x ** 2  pentru  x  în  ( 2 ,  4 ,  6 )} 
{2: 4, 4: 16, 6: 36}
Când cheile sunt șiruri simple, uneori este mai ușor să specificați perechi folosind argumentele cuvintelor cheie:
>>>
>>> dict ( sape = 4139 ,  guido = 4127 ,  jack = 4098 ) 
{'sape': 4139, 'jack': 4098, 'guido'

5.6. Tehnici looping 


Când se creează buclă prin dicționare, cheia și valoarea corespunzătoare pot fi preluate în același timp folosind metoda items () .
>>>
>>> knights  =  { 'gallahad' :  'pur' ,  'robin' :  'curajos' } 
>>> pentru  k ,  v  în  cavaleri . articole (): 
...     print ( k ,  v ) 
... 
gallahad pur și simplu 
curajos
Când se trece printr-o secvență, indicele de poziție și valoarea corespunzătoare pot fi preluate în același timp folosind funcția enumerate () .
>>>
>>> pentru  i ,  v  in  enumerate ([ 'tic' ,  'tac' ,  'toe' ]): 
...     print ( i ,  v ) 
... 
0 tic 
1 tac 
2 toe
Pentru a intra în două sau mai multe secvențe în același timp, intrările pot fi asociate cu funcția zip () .
>>>
>>> întrebări  =  [ 'nume' ,  'quest' ,  'culoarea preferata' ] 
>>> răspunsuri  =  [ 'Lancelot' ,  'Sfântul Graal' ,  'albastru' ] 
>>> pentru  q ,  o  în  ZIP ( întrebări ,  răspunsuri ): 
...     Print ( 'Care este {0} este {1}?.' . format ( q ,  a )) 
... 
Care este numele tău? Este lancelot.
Care este misiunea ta? Acesta este Sfântul Graal. 
Care este culoarea ta preferata? Este albastru.
Pentru a bifa o secvență în sens invers, mai întâi specificați secvența într-o direcție înainte și apoi apelați funcția inversă () .
>>>
>>> pentru  i  în sens  invers ( interval ( 1 ,  10 ,  2 )): 
...     print ( i ) 
... 
9 
7 
5 
3 
1
Pentru a bifa o secvență în ordinea sortată, utilizați funcția sort () care returnează o nouă listă sortată, lăsând în același timp sursa neschimbată.
>>>
>>> coș  =  [ 'mere' ,  'orange' ,  'măr' ,  'pere' ,  'orange' ,  'banana' ] 
>>> pentru  f  în  sortat ( set ( coș )): 
...     print ( f ) 
... 
mere 
banane 
portocale 
pere
Pentru a modifica o secvență pe care o repetați în interiorul bucla (de exemplu, pentru a duplica anumite elemente), este recomandat să creați o copie. Lovitura peste o secvență nu face implicit o copie. Notatia de felie face ca acest lucru deosebit de convenabil:
>>>
>>> cuvinte  =  [ 'cat' ,  'fereastră' ,  'defenestrate' ] 
>>> pentru  w  în  cuvinte [:]:   # Faceți buclă pe o copie a unei liste întregi. 
...     dacă  lămâie ( w )  >  6 : 
...         cuvinte . inserați ( 0 ,  w ) 
... 
>>> cuvinte 
['defenestrate', 'cat', 'window', 'defenestrate']

5.7. Mai multe despre condițiile 


Condițiile utilizate în instrucțiunile de timp și dacă pot conține orice operatori, nu doar comparații.
Operatorii de comparație în și nu în Verificați dacă apare o valoare (nu apare) într - o secvență. Operatorii este și este nu compara dacă două obiecte sunt într - adevăr același obiect; acest lucru contează doar pentru obiecte mutabile, cum ar fi listele. Toți operatorii de comparare au aceeași prioritate, care este mai mică decât cea a tuturor operatorilor numerici.
Comparațiile pot fi înlănțuite. De exemplu, un == c testează dacă a este mai mic decât b și în plus b este egal cu c .
Comparațiile pot fi combinate folosind operatorii booleani și și sau , iar rezultatul unei comparații (sau al oricărei alte expresii booleene) poate fi negat cu nu . Acestea au priorități mai mici decât operatorii de comparație; între ele, nu are cea mai mare prioritate și sau cea mai mică, astfel încât și nu Bsau C este echivalent cu (A și (nu B)) sau C . Ca întotdeauna, parantezele pot fi folosite pentru a exprima compoziția dorită.
Operatorii booleeni și și sau sau așa-numiții operatori de scurt-circuit : argumentele lor sunt evaluate de la stânga la dreapta și evaluarea se oprește de îndată ce rezultatul este determinat. De exemplu, dacă A și C sunt adevărate , dar B este fals, și și C nu evaluează expresia C . Atunci când este folosit ca valoare generală și nu ca booleană, valoarea de retur a operatorului de scurt-circuit este ultimul argument evaluat.
Este posibil să se atribuie rezultatul unei comparații sau al altei expresii booleene unei variabile. De exemplu,
>>>
>>> string1 ,  string2 ,  string3  =  '' ,  'Trondheim' ,  'Hammer Dance' 
>>> non_null  =  string1  sau  string2  sau  string3 
>>> non_null 
'Trondheim'
Rețineți că în Python, spre deosebire de C, atribuirea nu poate apărea în interiorul expresiilor. Programatorii C ar putea bâzâi despre acest lucru, dar evită o clasă comună de probleme întâlnite în programele C: tastând = într-o expresie când == a fost intenționată.

5.8. Compararea secvențelor și a altor tipuri 


Obiectele de secvență pot fi comparate cu alte obiecte cu același tip de secvență. Comparația folosește ordonarea lexicografică : mai întâi se compară primele două elemente și dacă acestea diferă, determină rezultatul comparației; dacă sunt egale, următoarele două elemente sunt comparate și așa mai departe, până când fiecare secvență este epuizată. Dacă două elemente care trebuie comparate sunt ele însele secvențe de același tip, comparația lexicografică se face recursiv. Dacă toate elementele a două secvențe se compară egale, secvențele sunt considerate egale. Dacă o secvență este o sub-secvență inițială a celeilalte, secvența mai scurtă este cea mai mică (mai mică). Ordonarea lexicografică pentru șiruri de caractere utilizează numărul codului Unicode pentru a comanda caractere individuale. Câteva exemple de comparații între secvențe de același tip:
( 1 ,  2 ,  3 )               <  ( 1 ,  2 ,  4 ) 
[ 1 ,  2 ,  3 ]               <  [ 1 ,  2 ,  4 ] 
'ABC'  <  'C'  <  'Pascal'  <  'Python' 
( 1 ,  2 ,  3 ,  4 )            <  ( 1 ,  2 ,  4 ) 
( 1 ,  2 )                  < ( 1 ,  2 ,  - 1 ) 
( 1 ,  2 ,  3 )              ==  ( 1,0 ,  2,0 ,  3,0 ) 
( 1 ,  2 ,  ( 'aa' ,  'ab' ))    <  ( 1 ,  2 ,  ( 'abc' ,  'a' ),  4 )
Rețineți că compararea obiectelor de diferite tipuri cu < sau > este legală, cu condiția ca obiectele să aibă metode de comparare adecvate. De exemplu, tipurile numerice mixte sunt comparate în funcție de valoarea lor numerică, deci 0 este egală cu 0,0, etc. Altfel, în loc să furnizeze o comandă arbitrară, interpretul va ridica o excepție TypeError .
Note de subsol
[1]Alte limbi pot returna obiectul mutant, care permite înlănțuirea metodei, cum ar fi d-> inserați ("a") -> eliminați ("b") -> sort (); .
[2]Apelarea tastelor d () va returna un obiect de vizualizare a dicționarului . Acceptă operații precum testul de membru și iterația, dar conținutul său nu este independent de dicționarul original - este doar o viziune .


Modulele 

Dacă renunțați la interpretul Python și îl introduceți din nou, definițiile pe care le-ați făcut (funcții și variabile) sunt pierdute. Prin urmare, dacă doriți să scrieți un program oarecum mai lung, vă recomandăm mai bine să utilizați un editor de text pentru a pregăti intrarea pentru interpret și pentru ao executa cu acel fișier ca intrare. Acest lucru este cunoscut ca crearea unui script . Pe măsură ce programul dvs. devine mai lung, vă recomandăm să îl împărțiți în mai multe fișiere pentru o întreținere mai ușoară. Poate doriți să utilizați o funcție utilă pe care ați scris-o în mai multe programe, fără a copia definiția acesteia în fiecare program.
Pentru a sprijini acest lucru, Python are o modalitate de a pune definițiile într-un fișier și de a le utiliza într-un script sau într-o instanță interactivă a interpretului. Un astfel de fișier este numit modul ; definițiile dintr-un modul pot fi importate în alte module sau în modulul principal (colecția de variabile la care aveți acces într-un script executat la nivel superior și în modul calculator).
Un modul este un fișier care conține definiții și declarații Python. Numele fișierului este numele modulului cu sufixul .py atașat. În cadrul unui modul, numele modulului (ca șir) este disponibil ca valoare a variabilei globale __name__ . De exemplu, utilizați editorul de text preferat pentru a crea un fișier numit fibo.py în directorul curent cu următorul conținut:
Modul # numere Fibonacci

def  fib ( n ):     # scrie seria Fibonacci pana la n 
    a ,  b  =  0 ,  1 în 
    timp ce  b  <  n : 
        print ( b ,  end = '' ) 
        a ,  b  =  b ,  a + b 
    print ()

def  fib2 ( n ):  # returnați seria Fibonacci până la n 
    rezultat  =  [] 
    a ,  b  =  0 ,  1 în 
    timp ce  b  <  n : 
        rezultat . append ( b ) 
        a ,  b  =  b ,  a + b 
    revenire  rezultat
Acum introduceți interpretul Python și importați acest modul cu următoarea comandă:
>>>
>>> import  fibo
Aceasta nu introduce numele funcțiilor definite în fibo direct în tabela simbolică curentă; intră doar în numele modulului fibo acolo. Folosind numele modulului puteți accesa funcțiile:
>>>
>>> fibo . fib ( 1000 ) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
>>> fibo . fib2 ( 100 ) 
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] 
>>> fibo . __name__ 
'fibo'
Dacă intenționați să utilizați o funcție de multe ori, puteți să o atribuiți unui nume local:
>>>
>>> fib  =  fibo . fib 
>>> fib ( 500 ) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377

6.1. Mai multe despre module 


Un modul poate conține instrucțiuni executabile, precum și definiții ale funcțiilor. Aceste instrucțiuni sunt destinate inițializării modulului. Ele sunt executate numai pentru prima dată când numele modulului este întâlnit într-o declarație de import. [1] (De asemenea, se execută dacă fișierul este executat ca script).
Fiecare modul are propria tabelă de simboluri private, care este utilizată ca tabelă simbol globală de toate funcțiile definite în modul. Astfel, autorul unui modul poate folosi variabilele globale în modul fără să se preocupe de ciocniri accidentale cu variabilele globale ale utilizatorului. Pe de altă parte, dacă știți ce faceți, puteți atinge variabilele globale ale unui modul cu aceeași notație folosită pentru a vă referi la funcțiile sale, modname.itemname .
Modulele pot importa alte module. Este obișnuit, dar nu este necesar să plasați toate declarațiile de import la începutul unui modul (sau script, de pildă). Numele modulelor importate sunt plasate în tabelul simbolului global al modulului de import.
Există o variantă a instrucțiunii de import care importează numele dintr-un modul direct în tabelul cu simboluri al modulului de import. De exemplu:
>>>
>>> de la  fibo  import  fib ,  fib2 
>>> fib ( 500 ) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Acest lucru nu introduce numele modulului din care se fac importurile în tabelul simbolurilor locale (așa că în exemplul de față fiboxul nu este definit).
Există chiar și o variantă pentru a importa toate denumirile pe care un modul le definește:
>>>
>>> de la  fibo  import  * 
>>> fib ( 500 ) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Aceasta importă toate denumirile, cu excepția celor care încep cu o subliniere ( _ ). În majoritatea cazurilor, programatorii Python nu utilizează această facilitate deoarece introduc un set necunoscut de nume în interpret, ascunzând eventual unele lucruri pe care le-ați definit deja.
Rețineți că, în general, practica importării * de la un modul sau un pachet este încruntată, deoarece provoacă adesea un cod ușor de citit. Cu toate acestea, este bine să o utilizați pentru a salva scrierea în sesiuni interactive.
Notă

Din motive de eficiență, fiecare modul este importat doar o singură sesiune de interpret. Prin urmare, dacă modificați modulele, trebuie să reporniți interpretul - sau, dacă este doar un modul pe care doriți să-l testați interactiv, utilizați imp.reload () , de ex. Import imp; imp.reload (modulename) .

6.1.1. Executarea modulelor ca scripturi 


Când rulați un modul Python cu
python  fibo . py  < argumentele >
codul din modul va fi executat, ca și cum l-ați importat, dar cu __name__ setat la "__main__" . Aceasta înseamnă că prin adăugarea acestui cod la sfârșitul modulului dvs.:
dacă  __name__  ==  "__main__" : 
    import  sys 
    fib ( int ( sys . argv [ 1 ]))
puteți face fișierul utilizabil ca script, precum și un modul importabil, deoarece codul care analizează linia de comandă rulează numai dacă modulul este executat ca fișier "principal":
$ python fibo.py 50
1 1 2 3 5 8 13 21 34
Dacă modulul este importat, codul nu este rulat:
>>>
>>> import  fibo 
>>>
Acest lucru este adesea folosit fie pentru a oferi o interfață de utilizare convenabilă unui modul, fie pentru scopuri de testare (funcționarea modulului ca script execută o suită de testare).

6.1.2. Calea de căutare a modulului 


Când un modul numit spam este importat, interpretul caută mai întâi un modul încorporat cu acest nume. Dacă nu este găsit, acesta caută apoi un fișier numit spam.py într-o listă de directoare date de variabila sys.path . sys.path este inițializată din aceste locații:
  • directorul care conține scriptul de intrare (sau directorul curent).
  • PYTHONPATH (o listă de nume de directoare, cu aceeași sintaxă ca variabila shellPATH ).
  • implicit pentru instalare.
După inițializare, programele Python pot modifica sys.path . Directorul care conține scriptul care se execută este plasat la începutul căii de căutare, înainte de calea standard a bibliotecii. Aceasta înseamnă că script-urile din directorul respectiv vor fi încărcate în locul modulelor cu același nume în directorul bibliotecii. Aceasta este o eroare, cu excepția cazului în care se intenționează înlocuirea. Vezi secțiunea Module standard pentru mai multe informații.

6.1.3. „Compilat“ fișiere Python 

Pentru a accelera modulele de încărcare, Python cachează versiunea compilată a fiecărui modul din directorul __pycache__ sub modulul de nume versiunea .pyc , unde versiunea codifică formatul fișierului compilat; conține, în general, numărul versiunii Python. De exemplu, în versiunea CPython 3.3, versiunea compilate a spam.py va fi stocată ca __pycache __ / spam.cpython-33.pyc . Această convenție de numire permite modulelor compilate din diferite versiuni și diferite versiuni ale Python să coexiste.
Python verifică data modificării sursei împotriva versiunii compilate pentru a vedea dacă este depășită și trebuie să fie recompilată. Acesta este un proces complet automat. De asemenea, modulele compilate sunt independente de platformă, astfel încât aceeași bibliotecă poate fi împărțită între sisteme cu arhitecturi diferite.
Python nu verifică memoria cache în două situații. În primul rând, întotdeauna recompilează și nu stochează rezultatul pentru modulul încărcat direct din linia de comandă. În al doilea rând, nu verifică memoria cache dacă nu există niciun modul sursă. Pentru a suporta o distribuție non-sursă (compilate numai), modulul compilat trebuie să fie în directorul sursă și nu trebuie să existe un modul sursă.
Câteva sfaturi pentru experți:
  • Puteți utiliza comutatoarele -O sau -OO din comanda Python pentru a reduce dimensiunea unui modul compilat. -O Comutatorul elimină afirma declarații, -OO comutatorul îndepårteazå afirma declarații și șiruri __doc__. Întrucât unele programe se pot baza pe faptul că acestea sunt disponibile, trebuie să utilizați această opțiune numai dacă știți ce faceți. Modulele "optimizate" au un .pyo mai degrabă decât un sufix .pyc și sunt de obicei mai mici. Eliberările viitoare pot schimba efectele optimizării.
  • Un program nu rulează mai repede când este citit dintr-un fișier .pyc sau .pyo decât atunci când este citit dintr-un fișier .py ; singurul lucru care este mai rapid despre fișierele .pyc sau .pyo este viteza cu care sunt încărcate.
  • Modulul compileall poate crea fișiere .pyc (sau fișiere .pyo când se utilizează -O ) pentru toate modulele dintr-un director.
  • Există mai multe detalii despre acest proces, inclusiv o diagramă a deciziilor, în PEP 3147.

6.2. Module standard 


Python vine cu o bibliotecă de module standard, descrisă într-un document separat, Python Library Reference ("Biblioteca de referință" de mai jos). Unele module sunt construite în interpret; acestea oferă acces la operații care nu fac parte din miezul limbii, dar sunt totuși construite, fie pentru eficiență, fie pentru a oferi acces la primitivi ai sistemului de operare, cum ar fi apelurile de sistem. Setul de astfel de module este o opțiune de configurare care depinde și de platforma de bază. De exemplu, modulul winreg este furnizat numai pe sistemele Windows. Un modul special merită o atenție deosebită: sys , care este construit în fiecare interpret Python. Variabilele sys.ps1 și sys.ps2 definiți șirurile utilizate ca mesaje primare și secundare:
>>>
>>> import  sys 
>>> sys . ps1 
'>>>' 
>>> sys . ps2 
'...' 
>>> sys . ps1  =  'C' ' 
C> print (' Yuck! ') 
Yuck! 
C>
Aceste două variabile sunt definite numai dacă interpretul este în modul interactiv.
Variabila sys.path este o listă de șiruri care determină calea de căutare a modulelor de interpretare. Aceasta este inițializată la o cale implicită luată din variabila de mediuPYTHONPATH sau dintr-o valoare implicită încorporată dacă PYTHONPATH nu este setat. Puteți să o modificați utilizând operațiuni de listă standard:
>>>
>>> import  sys 
>>> sys . calea . adăugați ( '/ ufs / guido / lib / python' )

6.3. Dir () Funcția 


Funcția built-in dir () este utilizată pentru a afla ce nume definește un modul. Returnează o listă ordonată de șiruri de caractere:
>>>
>>> import  fibo ,  sys 
>>> dir ( fibo ) 
[ '__name__', 'fib', 'fib2'] 
>>> dir ( sys )   
[ '__egginsert' '__displayhook__', '__doc__', '__excepthook__' , 
'__loader__', '__name__', '__package__', '__plen', '__stderr__', 
'__stdin__', '__stdout__', _clear_type_cache, 
_current_frames, _debugmallocstats, _getframe, _mercurial ',' _xoptions ', 
' abiflags ',' api_version ',' argv ',' base_exec_prefix ','base_prefix', 
'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 
'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info'
"excepție", "exec_prefix", "executabil", "ieșire", "flags", "float_info", 
"float_repr_style", "getcheckinterval", "getdefaultencoding", 
"getdjeckinflags", "getfilesystemencoding" ', 
' getrequsionlimit ',' getrefcount ',' getizeof ',' getwitchinterval ', 
' gettotalrefcount ',' gettrace ',' hash_info ',' hexversion ', 
' implementation ',' int_info ',' intern ',' maxsize ' 'maxunicode', 
'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 
'platform', 'prefix', 'ps1', 'setdlopenflags', 'setcheckinterval' 
'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 
'stderr', 'stdin', 'stdout', 'thread_info', 'versiune', 'version_info', 
„warnoptions „]
Fără argumente, dir () listează numele pe care le-ați definit în prezent:
>>>
>>> a  =  [ 1 ,  2 ,  3 ,  4 ,  5 ] 
>>> import  fibo 
>>> fib  =  fibo . fib 
>>> dir () 
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
Rețineți că acesta afișează toate tipurile de nume: variabile, module, funcții etc.
dir () nu conține numele funcțiilor și variabilelor încorporate. Dacă doriți o listă a acestora, acestea sunt definite în modulul standard builtins :
>>>
>>> import  Afi 
>>> dir ( Afi )   
[ 'ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 
'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 
'ChildProcessError', ' ConnectionAbortedError“, 'ConnectionError', 
'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 
'EOFError', 'Ellipsis', 'EnvironmentError', 'Excepție', 'fals', 
'fileexistserror', 'FileNotFoundError', 'FloatingPointError' , 
"FutureWarning", "GeneratorExit", "IOError "," ImportError ", 
" ImportWarning "," IndentationError "," IndexError "," InterruptedError ",
"IsADirectoryError", "KeyError", "KeyboardInterrupt", "LookupError", 
"MemoryError", "NameError", "None", "NotADirectoryError", 
"NotImplemented", "NotImplementedError", "OverflowError", 
PendingDeprecationWarning ',' 
RunError ', 
' RuntimeWarning ',' StopIteration ',' SyntaxError ',' SyntaxWarning ',' SystemError ', 
' SystemExit ',' TabError ', 
' PermissionError ',' ProcessLookupError ', ' ReferenceError ',' ResourceWarning ' "TimeoutError", "Adevărat", "TypeError", "UnboundLocalError", "UnicodeDecodeError", "UnicodeEncodeError", 
"UnicodeError", "UnicodeTranslateError", "UnicodeWarning", "UserWarning", 
"ValueError", "Avertisment", "ZeroDivisionError", "_", "__build_class__"
'__debug__', '__doc__', '__import__', '__name__', '__package__', 'ABS', 
'toate', 'orice', 'ascii', 'bin', 'bool', 'bytearray', „bytes ',' 
chr ',' classmethod ',' compile ',' complex ',' copyright ',' credits ', 
' delattr ',' dict ',' dir ',' divmod ' 'eval', 'exec', 'exit', 
'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 
'hash', 'help' ',' id ',' intrare ',' int ',' isinstance ',' issubclass ', 
'iter ',' len ',' local ',' map ',' max ',' memoryview ', 
' min ',' next ',' , "ord", "pow", "print", "proprietate", 
"quit", "gamă", "repr", "inversat 
" sort "," staticmethod "," str "," sum "," super "," tuplu "," tip "," vars "proprietățile ", " quit "," intervalul "," repr "," inversat "," rotund "," set "," setattr "," slice " , "super", "tuplu", "tip", "vars",proprietățile ", " quit "," intervalul "," repr "," inversat "," rotund "," set "," setattr "," slice " , "super", "tuplu", "tip", "vars",
 'Zip']

6.4. Pachete 


Pachetele reprezintă o modalitate de a structura spațiul de nume al modulelor Python utilizând "nume de module punctate". De exemplu, numele modulului AB desemneaza un submodul B într - un pachet numit A . La fel ca utilizarea modulelor salvează autorii diferitelor module de faptul că trebuie să vă faceți griji în legătură cu numele variabilelor globale ale fiecăruia, folosirea numelor de module întrerupte salvează autorii pachetelor multi-modul cum ar fi NumPy sau Biblioteca de Imagistică Python de la a fi nevoiți să vă faceți griji pentru fiecare numele altor module.
Să presupunem că doriți să proiectați o colecție de module (un "pachet") pentru o manipulare uniformă a fișierelor audio și a datelor de sunet. Există multe formate diferite de fișiere de sunet (de obicei, recunoscute de extensia lor, de exemplu: .wav , .aiff , .au ), astfel încât este posibil să fie nevoie să creați și să mențineți o colecție de module pentru convertirea între diferitele formate de fișiere. Există, de asemenea, multe operațiuni diferite pe care doriți să le efectuați pe date de sunet (cum ar fi amestecarea, adăugarea de ecouri, aplicarea unei funcții egalizatoare, crearea unui efect stereo artificial), astfel încât, în plus, veți scrie un flux neîntrerupt de module pentru a efectua aceste operațiuni. Iată o structură posibilă pentru pachetul dvs. (exprimată în termeni de sistem de fișiere ierarhic):
sunet / pachet de nivel superior
      __init__.py Inițializați pachetul de sunet
      formate / Subpachet pentru conversii în format de fișier
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      efecte / subpachet pentru efecte sonore
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filtre / subpachetare pentru filtre
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
La importul pachetului, Python caută directoarele pe sys.path căutând subdirectorul de pachete.
Cele __init__.py Fișierele sunt necesare pentru a face Python trateze directoarele ca pachete care conțin; acest lucru se face pentru a împiedica directoarele cu un nume comun, cum ar fi șirul , să ascundă neintenționat module valide care apar ulterior pe calea de căutare a modulelor. În cel mai simplu caz, __init__.py poate fi doar un fișier gol, dar poate executa și codul de inițializare pentru pachet sau poate seta variabila __all__ descrisă mai târziu.
Utilizatorii pachetului pot importa module individuale din pachet, de exemplu:
import  sound.effects.echo
Acest lucru încarcă submodul sound.effects.echo . Trebuie să fie menționată cu numele său complet.
sunet . efecte . echo . echofilter ( intrare ,  ieșire ,  întârziere = 0,7 ,  atten = 4 )
O modalitate alternativă de a importa submodul este:
de la  sound.effects  import  echo
De asemenea, se încarcă ecoul submodulului și îl face disponibil fără prefixul pachetului, astfel încât acesta poate fi folosit după cum urmează:
echo . echofilter ( intrare ,  ieșire ,  întârziere = 0,7 ,  atten = 4 )
O altă variantă este importul direct al funcției sau al variabilei dorite:
de la  sound.effects.echo  import  echofilter
Din nou, acest lucru încarcă ecou submodule , dar acest lucru face ca funcția sa echofilter () să fie direct disponibilă:
echofilter ( intrare ,  ieșire ,  întârziere = 0,7 ,  atten = 4 )
Rețineți că atunci când utilizați din elementul de import al pachetelor , elementul poate fi fie un submodul (sau subpachetul) al pachetului, fie un alt nume definit în pachet, ca o funcție, o clasă sau o variabilă. Instrucțiunea de import verifică mai întâi dacă articolul este definit în pachet; dacă nu, presupune că este un modul și încearcă să îl încarce. Dacă nu reușește să o găsească, o excepție ImportError este ridicată.
Contrar, atunci când se utilizează o sintaxă precum importul item.subitem.subsubitem , fiecare articol, cu excepția ultimului, trebuie să fie un pachet; ultimul element poate fi un modul sau un pachet, dar nu poate fi o clasă sau o funcție sau o variabilă definită în articolul anterior.

6.4.1. Importul * dintr-un pachet 


Acum ce se întâmplă atunci când utilizatorul scrie din importul sound.effects * În mod ideal, s-ar speranța că aceasta va ieși într-o oarecare măsură în sistemul de fișiere, va afla care submodule sunt prezente în pachet și le importă pe toate. Acest lucru ar putea dura mult timp, iar sub-modulele de import ar putea avea efecte secundare nedorite care ar trebui să se producă numai atunci când submodulul este importat explicit.
Singura soluție este ca autorul pachetului să furnizeze un indice explicit al pachetului. Instrucțiunea de import utilizează următoarea convenție: dacă codul __init__.py al unui pachet definește o listă numită __all__ , este considerată lista cu numele de module care ar trebui să fie importate când se întâlnește din importul de pachete * Depinde de autorul pachetului să păstreze actualizarea acestei liste atunci când este lansată o nouă versiune a pachetului. Autorii pachetelor pot, de asemenea, să decidă să nu o susțină, dacă nu văd o utilizare pentru importul * din pachetul lor. De exemplu, fișierul sunet / efecte / __ init__.py ar putea conține următorul cod:
__all__  =  [ "ecou" ,  "surround" ,  "invers" ]
Acest lucru ar însemna că importul * de la sound.effects ar importa cele trei submodule numite ale pachetului de sunet .
Dacă __all__ nu este definit, declarația de la Sound.Effects import * nu nu importa toate submodule din pachetul Sound.Effects în spațiul de nume curent; se asigură numai că au fost importate efecte sonore ale pachetului (eventual executând orice cod de inițializare în __init__.py) și apoi importă orice nume sunt definite în pachet. Aceasta include orice nume definite (și submodule încărcate explicit) de __init__.py . Acesta include, de asemenea, toate submodulele pachetului care au fost încărcate în mod explicit de declarațiile anterioare de import . Luați în considerare acest cod:
import  sound.effects.echo 
import  sound.effects.surround de 
la  sound.effects  import  *
În acest exemplu, modulele de ecou și surround sunt importate în spațiul de nume curent deoarece sunt definite în pachetul sound.effects atunci când declarația de import din ... este executată. (Aceasta funcționează și atunci când __all__ este definit.)
Deși anumite module sunt proiectate să exporte numai nume care urmează anumite modele atunci când utilizați import * , este încă considerată o practică nepotrivită în codul de producție.
Rețineți că nu este nimic în neregulă cu utilizarea din pachetul de import specific_submodule ! De fapt, aceasta este notația recomandată dacă modulul de import nu trebuie să utilizeze submodule cu același nume din diferite pachete.

6.4.2. Referințe-pachet intra 

Când pachetele sunt structurate în subpachete (ca în cazul pachetului de sunet din exemplu), puteți utiliza importurile absolute pentru a vă referi la submodulele pachetelor de frați. De exemplu, dacă modulul sound.filters.vocoder trebuie să utilizeze modulul ecou din pachetul sound.effects , acesta poate folosi din sound.effects import echo .
Puteți scrie , de asemenea , importurile relative, cu de la modulul de import numele sub formă de declarație de import. Aceste importuri utilizează puncte de vârf pentru a indica pachetele actuale și părțile implicate în importul relativ. De exemplu, de la modulul surround , este posibil să utilizați:
de la  .  importă  ecou 
din  ..  formate de import  din ..filters import egalizator
   
Rețineți că importurile relative se bazează pe numele modulului curent. Deoarece numele modulului principal este întotdeauna "__main__" , modulele destinate a fi utilizate ca modul principal al unei aplicații Python trebuie să utilizeze întotdeauna importuri absolute.

6.4.3. Pachete în mai multe directoare 

Pachetele suportă încă un atribut special, __path__ . Aceasta este inițializată pentru a fi o listă care conține numele directorului care ține fișierul __init__.py al pachetului înainte ca codul din acel fișier să fie executat. Această variabilă poate fi modificată; acest lucru afectează căutările viitoare pentru module și subpachete conținute în pachet.
În timp ce această caracteristică nu este adesea necesară, ea poate fi utilizată pentru a extinde setul de module găsite într-un pachet.
Note de subsol
[1]De fapt, definițiile funcțiilor sunt și "declarații" care sunt "executate"; execuția unei definiții a funcției la nivel de modul introduce numele funcției în tabela simbolică globală a modulului.

7. Intrări și ieșiri 

Există mai multe modalități de prezentare a rezultatelor unui program; datele pot fi tipărite într-o formă ușor de citit de om sau scrise într-un fișier pentru utilizare ulterioară. Acest capitol va discuta câteva posibilități.

7.1. Formatul de ieșire pentru fancier 


Până acum am întâlnit două modalități de scriere a valorilor: declarații de expresie și funcția print ()(A treia cale este folosirea metodei write () a obiectelor de fișier, fișierul de ieșire standard poate fi referit ca sys.stdout .
Deseori veți dori mai mult control asupra formatării ieșirii decât prin simpla imprimare a valorilor separate de spațiu. Există două moduri de formatare a ieșirii; prima modalitate este de a face toate manipularea string-ului; folosind operațiuni de tăiere în șir și operații de concatenare, puteți crea orice aspect pe care să-l puteți imagina. Tipul de șir are câteva metode care efectuează operații utile pentru ștanțarea șirurilor la o anumită lățime a coloanei; acestea vor fi discutate în scurt timp. A doua modalitate este de a folosi metoda str.format () .
Șir Modulul conține un șablon de clasă care oferă încă un alt mod de a înlocui valorile în șiruri.
O întrebare rămâne, bineînțeles: cum convertiți valori în șiruri de caractere? Din fericire, Python are modalități de a converti orice valoare într-un șir: treceți-l la funcțiile repr () sau str () .
Funcția str () are rolul de a returna reprezentări ale valorilor care pot fi citite de oameni, în timp ce repr () este destinat să genereze reprezentări care pot fi citite de interpret (sau vor forța un SyntaxError dacă nu există o sintaxă echivalentă). Pentru obiectele care nu au o reprezentare specială pentru consumul uman, str () va reveni la aceeași valoare ca și repr () . Multe valori, cum ar fi numere sau structuri precum liste și dicționare, au aceeași reprezentare utilizând oricare dintre funcții. Șirurile, în special, au două reprezentări distincte.
Cateva exemple:
>>>
>>> s  =  'Bună ziua, lume.' 
>>> str ( s ) 
"Bună ziua, lumea". 
>>> repr ( s ) 
" 'Bună ziua, lume.'" 
>>> str ( 1 / 7 ) 
'' 0.14285714285714285 
>>> x  =  10  *  3.25 
>>> y  =  200  *  200 
>>> s  =  „The valoarea lui x este '  +  repr ( x )  +  ', iar y este '  )  +  '...' 
>>> print ( s ) 
Valoarea lui x este 32.5, iar y este 40000 ... 
>>> # Repr () dintr-un șir adaugă citate șir și spate: 
... hello  =  'Bună ziua, lume \ n ' 
>>> hellos  =  repr ( alo ) 
>>> print ( hellos ) 
'Bună ziua, lume \ n' 
>>> # argumentul repr () poate fi orice obiect Python: 
... Repr (( x ,  y ,  ( 'spam' , „ouă“))) 
"(32.5, 40000, (" spam "," ouă "))"
Iată două modalități de a scrie o tabelă cu pătrate și cuburi:
>>>
>>> pentru  x  in  gama ( 1 ,  11 ): 
...     print ( repr ( x ) . Rjust ( 2 ),  repr ( x * x ) . Rjust ( 3 ),  end = '' ) 
...     # Notă utilizarea 'final' pe linia anterioară 
...     imprimare ( repr ( x * x * x ) . rjust ( 4)) 
... 
1 1 1 
2 4 8 
3 9 27 
4 16 64 
5 25 125 
6 36 216 
7 49 343 
8 64 512 
9 81 729 
10 100 000

>>> pentru  x  in  gama ( 1 ,  11 ): 
...     print ( '{0: 2d} {1: 3d} {2: 4d}' . Format ( x ,  x * x ,  x * x * x ) ) 
... 
1 1 1 
2 4 8 
3 9 27 
4 16 64 
5 25 125 
6 36 216 
7 49 343 
8 64 512 
9 81 729 
10 100 1000
(Rețineți că în primul exemplu, un spațiu între fiecare coloană a fost adăugat prin modul print () : acesta adaugă întotdeauna spații între argumentele sale.)
Acest exemplu demonstrează metoda str.rjust () a obiectelor șir, care justifică corect un șir dintr-un câmp de o anumită lățime, umplând-l cu spații în stânga. Există metode similare str.ljust () șistr.center () . Aceste metode nu scriu nimic, ci doar returnează un nou șir. Dacă șirul de introducere este prea lung, nu îl trunchiază, ci îl returnează neschimbat; acest lucru va afecta structura coloanei, dar de obicei este mai bună decât alternativa, care ar fi mincinoasă despre o valoare. (Dacă vreți cu adevărat trunchierea, puteți adăuga întotdeauna o operație cu felie, ca în x.ljust (n) [: n].)
Există o altă metodă, str.zfill () , care pătrunde într- un șir numeric în stânga cu zerouri. Înțelege semnele plus și minus:
>>>
>>> '12' . zfill ( 5 ) 
'00012' 
>>> '-3,14' . zfill ( 7 ) 
'-003.14' 
>>> '3.14159265359' . zfill ( 5 ) 
"3.14159265359"
Utilizarea de bază a metodei str.format () arată astfel:
>>>
>>> Print ( 'Suntem {} care spun "{}!"' . Format ( 'cavaleri' ,  'Ni' )) 
Noi suntem cavaleri care spun "Ni!"
Parantezele și caracterele din ele (numite câmpuri de format) sunt înlocuite cu obiectele transmise în metoda str.format () . Un număr din paranteze poate fi folosit pentru a se referi la poziția obiectului trecut în metoda str.format () .
>>>
>>> print ( '{0} și {1}' . Format ( "spam ,  'ouă' )) 
spam și ouă 
>>> print ( '{1} și {0}' . Format ( " spam ,  "ouă" )) 
ouă și spam
În cazul în care argumentele de cuvinte cheie sunt utilizate în metoda str.format () , valorile lor sunt menționate folosind numele argumentului.
>>>
>>> print ( 'This {food} este {adjectiv}.' . format ( 
...       food = 'spam' ,  adjectiv = 'absolut oribil' )) 
Acest spam este absolut oribil.
Argumentele poziționate și ale cuvintelor cheie pot fi combinate arbitrar:
>>>
>>> print ( 'Povestea {0}, {1} și {alt}.' . Format ( 'Bill' ,  'Manfred' , 
                                                       alt = 'Georg')) 
Povestea lui Bill, Manfred și Georg .
'a' (se aplică ascii () ), '! s' (se aplică str () ) și '! r' (se aplică repr () ) poate fi folosit pentru a converti valoarea înainte de a fi formatat:
>>>
>>> import  math 
>>> print ( 'Valoarea lui PI este de aproximativ {}.' . Format ( matematică . Pi )) 
Valoarea PI este de aproximativ 3.14159265359. 
>>> Print ( 'Valoarea lui PI este de aproximativ {!} R.' . Format ( matematică . Pi )) 
Valoarea PI este de aproximativ 3.141592653589793.
Un opțional ":" și un specificator de format poate urma numele câmpului. Acest lucru permite un control mai mare asupra modului în care este formatată valoarea. Exemplul de mai jos trasează Pi la trei locuri după zecimală.
>>>
>>> import  math 
>>> print ( 'Valoarea lui PI este de aproximativ {0: .3f}.' . Format ( matematică . Pi )) 
Valoarea PI este de aproximativ 3.142.
Trimiterea unui număr întreg după ':' va determina ca acest câmp să aibă un număr minim de caractere lățime. Acest lucru este util pentru a face mese destul.
>>>
>>> table  =  { 'Sjoerd' :  4127 ,  'Jack' :  4098 ,  'Dcab' :  7678 } 
>>> pentru  nume ,  telefon  în  tabel . articole (): 
...     imprimare ( '{0:10} ==> {1: 10d}' . format ( nume ,  telefon )) 
... 
Jack ==> 4098 
Dcab ==> 7678 
Sjoerd ==> 4127
Dacă aveți un șir de format foarte lung pe care nu doriți să-l împărțiți, ar fi bine dacă ați putea face referire la variabilele care urmează să fie formatate în funcție de nume în loc de poziție. Acest lucru se poate face prin simpla trecere a dictului și folosirea parantezelor [] pentru a accesa cheile
>>>
>>> tabel  =  { 'Sjoerd' :  4127 ,  'Jack' :  4098 ,  'Dcab' :  8637678 } 
>>> print ( „Jack: {0 [Jack]: d}; Sjoerd: {0 [Sjoerd]: d }; ' 
...       'Dcab: {0 [Dcab]: d}' . format ( tabel )) 
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
Acest lucru se poate face și prin trecerea tabelului ca argumente pentru cuvinte cheie cu notația '**'.
>>>
>>> Tabelul  =  { 'Sjoerd' :  4127 ,  'Jack' :  4098 ,  'Dcab' :  8637678 } 
>>> print ( 'Jack: {Jack: d} : d}“ . format ( ** tabelul )) 
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
Acest lucru este util în special în combinație cu funcția încorporată vars () , care returnează un dicționar care conține toate variabilele locale.
Pentru o prezentare completă a formatării șirului cu str.format () , consultați Sintaxa de formatare a șirului .

7.1.1. Formatarea șirului vechi 

% Operatorul poate fi de asemenea utilizat pentru formatarea șir de caractere. Aceasta interpretează argumentul stâng la fel ca un șir de format sprintf () -style pentru a fi aplicat argumentului drept și returnează șirul rezultat din această operație de formatare. De exemplu:
>>>
>>> import  math 
>>> print ( 'Valoarea lui PI este de aproximativ% 5.3f.'  %  Math . Pi ) 
Valoarea lui PI este de aproximativ 3.142.
Mai multe informații pot fi găsite în secțiunea Formatting String în stil printf .

7.2. Citirea și scrierea fișierelor 


open () returnează un obiect de fișier și este cel mai frecvent utilizat cu două argumente: open (nume fișier, mod) .
>>>
>>> f  =  deschis ( 'workfile' ,  'w' )
Primul argument este un șir care conține numele fișierului. Al doilea argument este un alt șir care conține câteva caractere care descriu modul în care fișierul va fi utilizat. Modul poate fi "r" atunci când fișierul va fi citit numai, "w" pentru scris doar (un fișier existent cu același nume va fi șters), iar"a" deschide fișierul pentru adăugare; toate datele scrise în fișier sunt adăugate automat la final. 'r +' deschide fișierul pentru citire și scriere. Modul Argumentul este opțională; "r" va fi asumat dacă este omis.
În mod normal, fișierele sunt deschise în modul text , adică citiți și scrieți șiruri din și în fișier, care sunt codificate într-o anumită codificare (implicit UTF-8). "b" atașat la modul deschide fișierul în modul binar : acum datele sunt citite și scrise sub formă de obiecte bytes. Acest mod ar trebui să fie utilizat pentru toate fișierele care nu conțin text.
În modul text, setarea implicită la citire este de a converti terminațiile liniei specifice platformei ( \ n pe Unix, \ r \ n pe Windows) la doar \ n . Când scrieți în modul text, implicit este să convertiți aparițiile \ n înapoi la terminalele liniei specifice platformei. Această modificare a datelor din fișiere în spatele scenei este bună pentru fișierele text, dar va corupe datele binare, cum ar fi cele din fișierele JPEGsau EXE . Fiți foarte atent să utilizați modul binar atunci când citiți și scrieți astfel de fișiere.

7.2.1. Metode ale obiectelor de fișiere 


Restul exemplelor din această secțiune presupun că un obiect de fișier numit f a fost deja creat.
Pentru a citi conținutul unui fișier, apelați f.read (size) , care citește o cantitate de date și o returnează ca un obiect șir sau bytes. dimensiunea este un argument numeric opțional. Atunci când mărimea este omisă sau negativă, întregul conținut al fișierului va fi citit și returnat; problema dvs. este dacă fișierul este de două ori mai mare decât memoria mașinii dvs. În caz contrar, la cele mai multe dimensiuni, octeții sunt citiți și returnați. Dacă sa ajuns la sfârșitul fișierului, f.read () va returna un șir gol ( '' ).
>>>
>>> f . read () 
'Acesta este întregul fișier. \ n' 
>>> f . citiți () 
''
f.readline () citește o singură linie din fișier; un caracter de linie nouă ( \ n ) este lăsat la sfârșitul șirului și este omis pe ultima linie a fișierului dacă fișierul nu se termină într-o linie nouă. Aceasta face ca valoarea de retur să fie neechivocă; dacă f.readline () returnează un șir gol, sa ajuns la sfârșitul fișierului, în timp ce o linie necompletată este reprezentată de '\ n' , un șir care conține doar o singură linie nouă.
>>>
>>> f . readline () 
'Aceasta este prima linie a fișierului. \ n' 
>>> f . readline () 
'A doua linie a fișierului \ n' 
>>> f . readline () 
''
Pentru citirea liniilor dintr-un fișier, puteți să le cuplați peste obiectul de fișier. Aceasta este memorie eficientă, rapidă și duce la un cod simplu:
>>>
>>> pentru  linia  in  f : 
...     print ( line ,  end = '' ) 
... 
Aceasta este prima linie a fisierului. 
A doua linie a dosarului
Dacă doriți să citiți toate liniile unui fișier dintr-o listă, puteți utiliza și lista (f) sau f.readlines () .
f.write (string) scrie conținutul șirului în fișier, returnând numărul de caractere scrise.
>>>
>>> f . scrie ( 'Acesta este un test \ n ' ) 
15
Pentru a scrie ceva diferit de un șir, trebuie mai întâi să fie convertit într-un șir:
>>>
>>> value  =  ( 'răspunsul' ,  42 ) 
>>> s  =  str ( valoare ) 
>>> f . scrie ( e ) 
18
f.tell () returnează un număr întreg care dă poziția curentă a obiectului fișierului în fișierul reprezentat ca număr de octeți de la începutul fișierului când este în modul binar și un număr opac înmodul text .
Pentru a modifica poziția obiectului fișierului, utilizați f.seek (offset, from_what) . Poziția este calculată prin adăugarea de compensare la un punct de referință; punctul de referință este selectat de argumentul from_what . from_what valoare de 0 măsuri de la începutul fișierului, 1 utilizează poziția fișierului curent și 2 utilizează sfârșitul fișierului ca punct de referință. from_what poate fi omis și defaults la 0, folosind începutul fișierului ca punct de referință.
>>>
>>> f  =  deschide ( 'workfile' ,  'rb +' ) 
>>> f . scrie ( b '0123456789abcdef' ) 
16 
>>> f . căutați ( 5 )      # Mergeți la cel de-al 6-lea octet din fișier 
5 
>>> f . citiți ( 1 ) 
b'5 ' 
>>> f . căutați ( - 3 ,  2 )  # Mergeți la cel de-al treilea byte înainte de finalul 
13 
>>> f .( 1 ) 
b'd '
În fișierele text (cele deschise fără un b în șirul de moduri) sunt permise doar căutările relative la începutul fișierului (excepția este căutată până la sfârșitul fișierului cu căutarea (0, 2) ) și singurele valori ofset valide sunt cele returnate de la f.tell () , sau zero. Orice altă valoare compensată produce comportament nedefinit.
Când ați terminat cu un fișier, apelați f.close () pentru al închide și a elibera toate resursele de sistem preluate de fișierul deschis. După ce a sunat f.close () , încercările de a utiliza obiectul de fișier vor eșua automat.
>>>
>>> f . închide () 
>>> f . citiți () 
Traceback (cel mai recent apel ultimul): 
  Fișierul "<stdin>" , rândul 1 , în ? 
ValueError : operare I / O pe fișier închis
Este o bună practică să folosească cu cuvinte cheie atunci când se ocupă cu obiecte de fișiere. Acest lucru are avantajul că fișierul este închis corespunzător după terminarea suitei sale, chiar dacă se ridică o excepție pe parcurs. Este, de asemenea, mult mai scurtă decât scrierea încercăriiechivalente - în cele din urmă blocuri:
>>>
>>> cu  open ( 'workfile' ,  'r' )  ca  f : 
...     read_data  =  f . citiți () 
>>> f . închis 
Adevărat
Obiectele de fișiere au câteva metode suplimentare, cum ar fi isatty () și truncate (), care sunt mai puțin utilizate; consultați Biblioteca Referință pentru un ghid complet al obiectelor de fișier.

7.2.2. Salvarea datelor structurate cu json


Șirurile pot fi ușor scrise și citite dintr-un fișier. Numerele fac un efort mai mic, deoarece metoda read () returneaza numai siruri de caractere, care trebuie sa fie transmise unei functii precum int () , care ia un sir ca '123' si isi returneaza valoarea numerica 123. Cand vrei sa salvați mai complexe tipuri de date, cum ar fi liste imbricate și dicționare, parsarea și serializarea manuală devine complicată.
Mai degrabă decât dacă utilizatorii au în mod constant scrierea și depanarea codului pentru a salva tipuri de date complicate în fișiere, Python vă permite să utilizați formatul popular de schimb de date numit JSON (JavaScript Object Notation) . Modulul standard denumit json poate lua ierarhiile de date Python și le poate converti în reprezentări de șir; acest proces se numește serializare . Reconstruirea datelor din reprezentarea șirului se numește deserializare . Între serializarea și deserializarea, șirul reprezentând obiectul ar fi putut fi stocat într-un fișier sau date sau trimis printr-o conexiune de rețea la o anumită mașină îndepărtată.
Notă

Formatul JSON este utilizat în mod obișnuit de aplicații moderne pentru a permite schimbul de date. Mulți programatori sunt deja familiarizați cu acesta, ceea ce îl face o alegere bună pentru interoperabilitate.
Dacă aveți un obiect x , puteți vizualiza reprezentarea șirului JSON cu o linie simplă de cod:
>>>
>>> json . haldele ([ 1 ,  "simplu" ,  "listă" ]) 
"[1," simplu "," listă "
O altă variantă a funcției dumps () , denumită dump () , serializează pur și simplu obiectul într-un fișier text . Deci, dacă f este un obiect de fișier text deschis pentru scriere, putem face acest lucru:
json . dump ( x ,  f )
Pentru a decoda obiectul din nou, dacă f este un obiect de fișier text care a fost deschis pentru citire:
x  =  json . sarcină ( f )
Această tehnică de serializare simplă poate gestiona liste și dicționare, însă serializarea instanțelor de clasă arbitrare din JSON necesită un efort suplimentar. Referința pentru modulul json conține o explicație a acestui lucru.
Vezi si

pickle - modulul pickle
Spre deosebire de JSON , pickle este un protocol care permite serializarea obiectelor Python arbitrar complexe. Ca atare, este specific pentru Python și nu poate fi folosit pentru a comunica cu aplicații scrise în alte limbi. Este, de asemenea, nesigur în mod implicit: deserializarea datelor de muraturi care provin dintr-o sursă neîncrezătoare pot executa un cod arbitrar, dacă datele au fost create de un atacator calificat.


8. Erori și excepții 

Până acum mesajele de eroare nu au fost mai mult decât menționate, dar dacă ați încercat exemplele pe care le-ați văzut probabil unele. Există (cel puțin) două tipuri de erori distincte: erori de sintaxă și excepții .

8.1. Erori de sintaxă 


Erorile de sintaxă, cunoscute și sub numele de erori de parsing, sunt probabil cele mai comune tipuri de reclamații pe care le obțineți în timp ce învățați încă Python:
>>>
>>> în timp ce  Print True  ( "Bună ziua" )   Fișier "<stdin>", linia 1, în?     în timp ce True print ('Hello world')                    ^ SyntaxError: sintaxă invalidă




Parserul repetă linia infracțională și afișează o mică "săgeată" care indică cel mai devreme punct din linia unde a fost detectată eroarea. Eroarea este cauzată de (sau cel puțin detectată) de tokenul precedent de săgeată: în exemplu, eroarea este detectată la funcția print () , deoarece un colon ( ':' ) lipsește înainte de aceasta. Numele fișierului și numărul liniei sunt tipărite, astfel încât să știți unde să căutați în cazul în care intrarea a venit dintr-un script.

8.2. Excepții 


Chiar dacă o declarație sau o expresie este corectă din punct de vedere sintactic, poate provoca o eroare atunci când se face o încercare de ao executa. Erori detectate în timpul execuției sunt numite excepții și nu sunt necondiționat fatale: în curând veți afla cum să le gestionați în programele Python. Cele mai multe excepții nu sunt tratate de programe, cu toate acestea, și rezultă în mesaje de eroare, după cum se arată aici:
>>>
>>> 10  *  ( 1 / 0 ) 
Traceback (apel cele mai recente Ultima): 
  Fișier "<stdin>" , linia 1 , în ? 
ZeroDivisionError : împărțire la zero 
>>> 4  +  spam * 3 
Traceback (ultimul apel ultimul): 
  Fișierul "<stdin>" , linia 1 , în ? 
NumeError : numele "spam" nu este definit 
>>> '2'  +  2 
Traceback (cel mai recent apel ultimul): 
  Fișierul "<stdin>", în ? 
TypeError : Imposibil de convertit obiectul 'int' la str implicit
Ultimul rând al mesajului de eroare indică ce sa întâmplat. Excepțiile vin în diferite tipuri, iar tipul este tipărit ca parte a mesajului: tipurile din exemplu sunt ZeroDivisionError , NameError și TypeError . Șirul imprimat ca tip de excepție este numele excepției integrate care a apărut. Acest lucru este valabil pentru toate excepțiile integrate, dar nu este necesar să fie adevărat pentru excepțiile definite de utilizator (deși este o convenție utilă). Numele excepționale standard sunt identificatorii încorporați (nu sunt cuvinte cheie rezervate).
Restul liniei oferă detalii pe baza tipului de excepție și a ceea ce a cauzat-o.
Partea anterioară a mesajului de eroare arată contextul în care sa produs excepția, sub forma unei traseback de stivă. În general, acesta conține o linie de sursă a liniei sursă de traseback; cu toate acestea, nu va afișa liniile citite de la intrarea standard.
Excepțiile construite listează excepțiile încorporate și semnificațiile acestora.

8.3. Excepții de manipulare 


Este posibil să scrieți programe care să trateze excepțiile selectate. Uitați-vă la exemplul următor, care solicită utilizatorului introducerea până la introducerea unui număr întreg valid, dar permite utilizatorului să întrerupă programul (folosind Control-C sau orice suport acceptă sistemul de operare); rețineți că o întrerupere generată de utilizator este semnalizată prin ridicarea excepției KeyboardInterrupt .
>>>
>>> în timp ce  Adevărat : 
...     încercați : 
...         x  =  int ( introduceți ( "Introduceți un număr:" )) 
...         pauză 
...     cu excepția  ValueError : 
...         print ( "Oops! un număr valid, încercați din nou ... " ) 
...
Instrucțiunea try funcționează după cum urmează.
  • În primul rând, clauza try (declarația (e) între încercare și cu excepția cuvintelor cheie) este executat.
  • Dacă nu se produce nicio excepție, clauza excepțională este omisă și executarea instrucțiunii try este terminată.
  • Dacă se produce o excepție în timpul executării clauzei de încercare, restul clauzei este omisă. Apoi , în cazul în care tipul său se potrivește cu excepția numit după excepția cuvintelor cheie, clauza except este executat, iar apoi de execuție este după încercare declarația.
  • Dacă apare o excepție care nu se potrivește cu excepția numită în clauza excepțională, aceasta este transmisă unor instrucțiuni exterioare de încercare ; dacă nu se găsește niciun manipulator, este o excepție nefolosită și execuția se oprește cu un mesaj așa cum este arătat mai sus.
instrucțiune try poate avea mai mult de o excepție, cu excepția clauzei, pentru a specifica manipulatorii pentru diferite excepții. La cel mult un handler va fi executat. Handlerele gestionează exclusiv excepțiile care apar în clauza de încercare corespunzătoare, nu și în alte manipulatoare ale aceleiași instrucțiuni de încercare . O clauză excepțională poate numi mai multe excepții ca o paranteză paranteză, de exemplu:
...  cu excepția  ( RuntimeError ,  TypeError ,  NameError ): 
...      pass
Ultimul, cu excepția clauzei, poate omite numele de excepție, pentru a servi drept wildcard. Utilizați acest lucru cu precauție extremă, deoarece este ușor să mascați o eroare de programare reală în acest fel! De asemenea, poate fi folosit pentru a imprima un mesaj de eroare și apoi re-ridicați excepția (permițând unui apelant să facă față și excepției):
import  sys

încercați : 
    f  =  open ( 'myfile.txt' ) 
    s  =  f . readline () 
    i  =  int ( s . benzi ()) cu 
excepția  IOError  ca  err : 
    print ( "eroare I / O: {0}" . format ( err )) cu 
excepția  ValueError : 
    print ( „Nu am putut converti datele la un întreg. " ) 
cu excepția : 
    print ( " Eroare neașteptată: " ,  sys .exc_info () [ 0 ]) 
    crește
Încercare ... cu excepția declarație are o opțională clauză else , care, atunci când este prezent, trebuie să urmeze toate , cu excepția clauzelor. Este util pentru codul care trebuie executat dacă clauza de încercare nu ridică o excepție. De exemplu:
pentru  arg  în  sys . argv [ 1 :]: 
    încercați : 
        f  =  deschis ( arg ,  'r' ) , cu 
    excepția  IOError : 
        imprimare ( 'nu se poate deschide' ,  arg ) 
    altceva : de 
        imprimare ( arg ,  'are' ,  len ( f . readlines ()),  " linii " ) 
        f . închide ()
Utilizarea altfel clauza este mai bună decât adăugarea de cod suplimentar la încercare clauza deoarece evită prinderea în mod accidental o excepție care nu a fost ridicată de codul fiind protejat de încercare ... cu excepția declarație.
Când apare o excepție, poate avea o valoare asociată, cunoscută și ca argumentul excepției Prezența și tipul argumentului depind de tipul excepției.
Clauza excepțională poate specifica o variabilă după numele excepției. Variabila este legată de o instanță de excepție cu argumentele stocate în instanța.args . Pentru comoditate, instanța de excepție definește __str __ () astfel încât argumentele pot fi imprimate direct fără a fi nevoie să se facă referință .args . De asemenea, se poate instantiza o exceptie inainte de ao ridica si de a adauga orice atribut dupa dorinta.
>>>
>>> încercați : 
...    ridica  excepție ( 'spam - ului' ,  'ouă' ) 
... cu excepția  Excepție  ca  inst : 
... de    imprimare ( de tip ( Inst ))     # excepției de exemplu 
...    imprimare ( inst . Args )      # argumente stocate în .args 
...    print ( inst )           # __str__ permite args să fie imprimate direct, 
...                         # dar pot fi suprascrise în subclasele de excepție 
...    x , y  =  inst . ARGS      # despachetați args 
...    print ( 'x =' ,  x ) 
...    print ( 'y =' ,  y ) 
... 
<class 'Excepție'> 
( 'spam 'ouă') 
( "spam , "ouă") 
x = spam 
y = ouă
Dacă o excepție are argumente, ele sunt tipărite ca ultima parte ("detaliu") a mesajului pentru excepții nefolosite.
Excepții de manipulare nu se ocupă doar de excepții dacă apar imediat în clauza de încercare, dar și în cazul în care apar în interiorul funcțiilor care sunt numite (chiar indirect) în clauza de încercare. De exemplu:
>>>
>>> def  this_fails (): 
...     x  =  1 / 0 
... 
>>> try : 
...     this_fails () 
... cu excepția  ZeroDivisionError  ca  ERR : 
... de     imprimare ( „eroare de manipulare run-time: " ,  err ) 
... 
Manipularea erorii run-time: int divizare sau modulo la zero

8.4. Ridicarea excepțiilor 


Instrucțiunea de creare permite programatorului să forțeze o excepție specificată. De exemplu:
>>>
>>> ridica  Traseback NameError ( 'HiThere' ) 
(ultimul apel ultimul): 
  Fișierul "<stdin>" , linia 1 , în ? 
NumeError : HiThere
Singurul argument pe care îl ridică indică excepția care trebuie ridicată. Aceasta trebuie să fie o instanță de excepție sau o clasă de excepție (o clasă care derivă din Excepție ).
Dacă trebuie să determinați dacă a fost ridicată o excepție, dar nu intenționați să o gestionați, o formă mai simplă a instrucțiunii de ridicare vă permite să re-ridicați excepția:
>>>
>>> încercați : 
...     ridica  NameError ( 'HiThere' ) 
... cu excepția  NameError : 
...     print ( 'O excepție a zburat!' ) 
...     ridica 
... 
O excepție a zburat! 
Traceback (cel mai recent apel ultimul): 
  Fișierul "<stdin>" , linia 2 , în ? 
NumeError : HiThere

8.5. Excepții definite de utilizator 


Programele își pot numi excepțiile prin crearea unei noi clase de excepție (consultați clasele pentru mai multe despre clasele Python). Excepțiile ar trebui, de obicei, să fie derivate din clasa de excepție, direct sau indirect. De exemplu:
>>>
>>> clasa  MyError ( excepție ): 
...     def  __init__ ( sine ,  valoare ): 
...         sine . Valoarea  =  valoarea 
...     def  __str__ ( auto ): 
...         întoarcere  Repr ( auto . valoare ) 
... 
>>> încercați : 
...     ridica  MyError ( 2 * 2 ) 
... cu excepția  MyError  ca  e :
... de     imprimare ( 'excepție mea a avut loc, valoarea:' ,  e . Valoarea ) 
... 
excepție mea a avut loc, valoarea: 4 
>>> ridica  MyError ( '! Oops' ) 
Traceback (apel cele mai recente Ultima): 
  Fișier „< stdin> " , linia 1 , în ? 
__main __. MyError : "Oops!"
În acest exemplu, valoarea implicită __init __ () a excepției a fost înlocuită. Noul comportament creează pur și simplu atributul value . Aceasta înlocuiește comportamentul implicit al creării atributului args .
Clasele de excepție pot fi definite care fac ceea ce poate face orice altă clasă, dar de obicei sunt păstrate simple, adesea oferind doar un număr de atribute care permit ca informațiile despre eroare să fie extrase de către manipulanți pentru excepție. Când se creează un modul care poate genera mai multe erori distincte, o practică obișnuită este crearea unei clase de bază pentru excepțiile definite de acel modul și a unei subclase care să creeze clase excepționale specifice pentru diferite condiții de eroare:
Clasa de  eroare ( Excepție ): 
    „“ „clasa de baza pentru excepții în acest modul“ „“ 
    trecere

class  InputError ( Error ): 
    "" "Excepție ridicată pentru erori la intrare.

    Atribute: 
        expresie - expresie de intrare în care a apărut 
        mesajul 
eroare - explicarea erorii     "" "

    def  __init__ ( sine ,  expresie ,  mesaj ): 
        sine . expresie  =  expresie de 
        sine . mesaj  =  mesaj

Class  TransitionError ( Error ): 
    "" Crescut atunci când o operație încearcă o tranziție de stat care nu este 
    permisă.

    Atribute: 
        precedent - starea de la începutul tranziției 
        următoare - încercarea unui nou 
        mesaj de 
stare - explicarea motivului pentru care nu este permisă tranziția specifică     "" "

    def  __init__ ( sine ,  precedent ,  următor ,  mesaj ): 
        sine . anterior  =  anterior de 
        sine . next  =  next 
        sine . mesaj  =  mesaj
Cele mai multe excepții sunt definite cu nume care se termină în "Eroare", similar cu denumirea excepțiilor standard.
Multe module standard definesc propriile excepții de a raporta erorile care pot apărea în funcțiile pe care le definesc. Mai multe informații despre clase sunt prezentate în capitolele Clase .

8.6. Definirea acțiunilor de curățare 


Instrucțiunea try are o altă clauză opțională, care este destinată să definească acțiunile de curățare care trebuie executate în toate circumstanțele. De exemplu:
>>>
>>> încercați : 
...     ridicați  KeyboardInterrupt 
... în sfârșit : 
...     print ( "La revedere, lumea!" ) 
... 
La revedere, lume! 
KeyboardInterrupt
clauză finală este întotdeauna executată înainte de a părăsi instrucțiunea try , indiferent dacă a apărut o excepție sau nu. Atunci când a avut loc o excepție în încercați clauza și nu a fost tratată printr - o , cu excepția clauza (sau a avut loc într - afară sau altceva clauza), acesta este re-raise după ce în cele din urmă clauza a fost executată. În cele din urmă clauză este , de asemenea , executat „pe cale de ieșire“ , atunci când orice altă clauză de încercare declarația este lăsată printr - pauză , să continue sau a reveni declarație. Un exemplu mai complicat:
>>>
>>> def  divide ( x ,  y ): 
...     încercați : 
...         rezultatul  =  x  /  y 
... cu     excepția  ZeroDivisionError : 
...         Print ( "diviziune de la zero!" ) 
...     altceva : 
...         print ( "rezultatul este" ,  rezultat ) 
... în     cele din urmă : 
...         print ( "executând definitiv clauza" ) 
... 
>>> divide ( 2 , 1 ) 
rezultatul este 2.0 
executând în cele din urmă clauza 
>>> diviziunea ( 2 ,  0 ) 
împărțirea la zero! 
executând în final clauza 
>>> divide ( "2" ,  "1" ) 
executând în cele din urmă clauza 
Traceback (ultimul apel ultimul): 
  Fișier "<stdin>" , rândul 1 , în ? 
  Fișierul "<stdin>" , rândul 3 , în diviziune 
TypeError : tipuri de operand neacceptate pentru /: 'str' și 'str'
După cum puteți vedea, clauza finală este executată în orice caz. TypeError ridicată prin împărțirea două șiruri nu este tratată de către excepția clauzei și , prin urmare , reraise după ce în final clauza a fost executată.
În aplicațiile din lumea reală, clauza finală este utilă pentru eliberarea de resurse externe (cum ar fi fișiere sau conexiuni de rețea), indiferent dacă utilizarea resurselor a avut succes.

8.7. Acțiuni de curățare predefinite 


Unele obiecte definesc acțiunile standard de curățare care trebuie întreprinse atunci când obiectul nu mai este necesar, indiferent dacă operația care utilizează obiectul a reușit sau nu a reușit. Uitați-vă la următorul exemplu, care încearcă să deschidă un fișier și să imprime conținutul acestuia pe ecran.
pentru  linia  în  deschisă ( "myfile.txt" ): 
    imprimare ( linia ,  end = "" )
Problema cu acest cod este că ea lasă fișierul deschis pentru o perioadă nedeterminată de timp după ce această parte a codului a terminat executarea. Aceasta nu este o problemă în scenarii simple, dar poate fi o problemă pentru aplicațiile mai mari. Instrucțiunea cu permite ca obiectele ca fișierele să fie utilizate într-un mod care să asigure că acestea sunt întotdeauna curățate prompt și corect.
cu  open ( "myfile.txt" )  ca  f : 
    pentru  linia  în  f : 
        print ( linia ,  capăt = "" )
După executarea instrucțiunii, fișierul f este întotdeauna închis, chiar dacă a apărut o problemă în timpul procesării liniilor. Obiectele care, ca fișiere, oferă acțiuni de curățare predefinite, vor indica acest lucru în documentația lor.


9. Clasele 

În comparație cu alte limbi de programare, mecanismul clasei Python adaugă clase cu un minim de sintaxă și semantică noi. Este un amestec al mecanismelor de clasă descoperite în C ++ și Modula-3. Clasele Python oferă toate caracteristicile standard ale programării orientate pe obiecte: mecanismul de moștenire a clasei permite mai multor clase de bază, o clasă derivată poate suprascrie orice metodă a clasei sau clasei sale de bază și o metodă poate apela metoda unei clase de bază cu același nume . Obiectele pot conține cantități arbitrare și tipuri de date. Așa cum este valabil și pentru module, clasele participă la natura dinamică a Python: ele sunt create în timpul execuției și pot fi modificate ulterior după crearea.
În terminologia C ++, în mod normal, membrii clasei (inclusiv membrii de date) sunt publici (cu excepția celor de mai jos , Variabile private ) și toate funcțiile membre sunt virtuale . Ca și în Modula-3, nu există contorii pentru referirea membrilor obiectului din metodele sale: funcția de metodă este declarată cu un prim argument explicit reprezentând obiectul, care este furnizat implicit de apel. Ca și în Smalltalk, clasele sunt obiecte. Aceasta oferă semantică pentru import și redenumire. Spre deosebire de C ++ și Modula-3, tipurile încorporate pot fi folosite ca clase de bază pentru extensie de către utilizator. De asemenea, ca în C ++, majoritatea operatorilor încorporați cu sintaxă specială (operatori aritmetici, subscripting etc.) pot fi redefiniți pentru instanțe de clasă.
(Lipsa terminologiei universal acceptate pentru a vorbi despre clase, voi folosi ocazional termenii Smalltalk și C ++. Aș folosi termeni Modula-3, deoarece semantica orientată pe obiecte este mai apropiată de cea a lui Python decât C ++, dar mă aștept ca puțini cititori au auzit de ea.)

9.1. Un cuvânt despre nume și obiecte 

Obiectele au individualitate, iar mai multe nume (în mai multe domenii) pot fi legate la același obiect. Aceasta este cunoscută sub numele de aliasing în alte limbi. Acest lucru nu este de obicei apreciat la prima vedere la Python și poate fi ignorat în siguranță atunci când se ocupă cu tipuri de bază imuabile (numere, șiruri, tuple). Cu toate acestea, aliasingul are un efect surprinzător posibil asupra semanticii codului Python care implică obiecte mutabile, cum ar fi listele, dicționarele și cele mai multe alte tipuri. Aceasta este de obicei folosită în beneficiul programului, deoarece pseudonimurile se comportă ca indicii în anumite privințe. De exemplu, trecerea unui obiect este ieftină, deoarece doar un indicator este trecut prin implementare; și dacă o funcție modifică un obiect trecut ca argument, apelantul va vedea schimbarea - aceasta elimină necesitatea existenței a două mecanisme diferite de trecere a argumentelor ca în Pascal.

9.2. Python Scopes și Namespaces 

Înainte de a introduce clase, trebuie să vă spun mai întâi despre regulile de aplicare a Python. Definițiile de clasă joacă niște trucuri îngrijite cu spații de nume și trebuie să știți cum funcționează domeniile și spațiile de nume pentru a înțelege pe deplin ce se întâmplă. De altfel, cunoștințele despre acest subiect sunt utile pentru orice programator Python avansat.
Să începem cu câteva definiții.
Un spațiu de nume este o mapare de la nume la obiecte. Cele mai multe spații de nume sunt implementate în prezent ca dicționare Python, dar în mod normal nu sunt vizibile în nici un fel (cu excepția performanței) și se pot schimba în viitor. Exemple de spații de nume sunt: ​​setul de nume încorporate (care conțin funcții precum abs () și nume excepționale construite); numele globale dintr-un modul; și numele locale într-o invocare a funcțiilor. Într-un sens, mulțimea de atribute ale unui obiect formează și un spațiu de nume. Lucrul important de știut despre spațiile de nume este că nu există absolut nicio legătură între numele în spații de nume diferite; de exemplu, două module diferite pot să definească o funcție maximizată fără confuzie - utilizatorii modulelor trebuie să o prefixeze cu numele modulului.
Apropo, folosesc atributul cuvânt pentru orice nume care urmează un punct - de exemplu, în expresia z.real , real este un atribut al obiectului z . În mod strict vorbind, referințele la nume în module sunt referințe atribute: în expresia modname.funcname , modname este un obiect de module și funcnameeste un atribut al acestuia. În acest caz se întâmplă o mapare simplă între atributele modulului și numele globale definite în modul: aceștia împărtășesc același spațiu de nume! [1]
Atributele pot fi doar pentru citire sau scriere. În ultimul caz, este posibilă alocarea atributelor. Atributele modulului sunt inscriptibile: puteți scrie modname.the_answer 42 . Atributele de scriere pot fi șterse și cu instrucțiunea del . De exemplu, del modname.the_answer va elimina atributul the_answer de la obiectul numit modname .
Spațiile de nume sunt create în momente diferite și au durate diferite de viață. Spațiul de nume care conține numele încorporate este creat atunci când interpretul Python pornește și nu este șters niciodată. Spațiul de nume global pentru un modul este creat atunci când se citește definiția modulului; în mod normal, numerele de module ale modulelor durează și până când interpretul se oprește. Instrucțiunile executate de invocarea de nivel superior a interpretului, fie citite dintr-un fișier script, fie interactiv, sunt considerate ca parte a unui modul numit __main__ , deci au propriul lor spațiu de nume global. (Numele încorporate trăiesc de asemenea într-un modul, acest lucru se numește builtins .)
Spațiul de nume local pentru o funcție este creat atunci când funcția este apelată și șters atunci când funcția returnează sau ridică o excepție care nu este tratată în cadrul funcției. (De fapt, uitarea ar fi o modalitate mai bună de a descrie ce se întâmplă de fapt). Desigur, invocările recursive au fiecare propriul lor spațiu de nume local.
Un domeniu este o regiune textuală a unui program Python în care un spațiu de nume este direct accesibil. "Direct accesibil" înseamnă că o referință necalificată la un nume încearcă să găsească numele în spațiul de nume.
Deși scopurile sunt determinate static, ele sunt folosite dinamic. În orice moment în timpul execuției, există cel puțin trei domenii imbricate ale căror spații de nume sunt direct accesibile:
  • domeniul de aplicare cel mai intim, care este căutat în primul rând, conține numele locale
  • domeniile oricărei funcții de închidere, care sunt căutate începând cu cel mai apropiat domeniu de aplicare, conțin nume non-locale, dar și non-globale
  • următorul domeniu de aplicare conține numele global al modulului curent
  • cel mai îndepărtat domeniu (ultimul căutat) este spațiul de nume care conține numele încorporate
Dacă un nume este declarat global, atunci toate referințele și alocările merg direct la domeniul de aplicare intermediar care conține numele global al modulului. Pentru a rebrand variabilele găsite în afara domeniului interior, se poate folosi declarația nonlocală ; dacă nu sunt declarate nonlocale, acele variabile sunt doar pentru citire (încercarea de a scrie la o astfel de variabilă va crea pur și simplu o nouă variabilă locală în interiorul domeniului interior, lăsând neschimbată variabila externă identică).
De obicei, domeniul de aplicare local se referă la numele local al funcției curente (textuale). În afara funcțiilor, domeniul de aplicare local se referă la același spațiu de nume ca și domeniul global: spațiul de nume al modulului. Definițiile de clasă plasează încă un spațiu de nume în domeniul de aplicare local.
Este important să ne dăm seama că domeniile sunt determinate textual: domeniul global al unei funcții definite într-un modul este spațiul de nume al modulului, indiferent de unde sau prin ce nume se numește funcția. Pe de altă parte, căutarea reală a numelor se face dinamic, la momentul executării - totuși, definiția limbii evoluează spre rezolvarea numelui static, la momentul "compilației", deci nu vă bazați pe rezoluția dinamică a numelui! (De fapt, variabilele locale sunt deja determinate static.)
O chestiune specială a lui Python este că - dacă nu există nicio declarație globală - atribuțiile la nume intră întotdeauna în cel mai luminos scop. Atribuțiile nu copiază date - ci doar leagă numele la obiecte. Același lucru este valabil și pentru ștergeri: instruciunea del x elimină legarea lui x din spațiul de nume referit de domeniul de aplicare local. De fapt, toate operațiunile care introduc nume noi utilizează domeniul de aplicare local: în special, declarațiile de import și definițiile funcțiilor leagă numele modulului sau al funcției în domeniul local.
Declarația globală poate fi utilizată pentru a indica faptul că anumite variabile trăiesc în sfera globală și ar trebui să revină acolo; nelocal declarație indică faptul că anumite variabile trăiesc într - un domeniu de aplicare împrejmuitor și ar trebui să fie de rebound acolo.

9.2.1. Exemple de spații și nume de case 

Acesta este un exemplu care demonstrează modul de referință a diferitelor domenii și spații de nume și modul în care influența globală și nelocală afectează variația obligatorie:
def scope_test():
    def do_local():
        spam = "local spam"
    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"
    def do_global():
        global spam
        spam = "global spam"
    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
Rezultatul exemplului de cod este:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
Notă modul în care locale alocare (care este implicit) nu a modificat scope_test e legarea de spam - ului . Nelocal Atribuirea schimbat scope_test e legarea spam - ului , iar la nivel mondial atribuirea schimbat legării la nivel de modul.
De asemenea, puteți vedea că nu a existat nici o obligație anterioară pentru spam înainte de atribuirea globală .

9.3. O primă privire la clase 

Clasele introduc un pic de sintaxă nouă, trei tipuri de obiecte noi și câteva semantici noi.

9.3.1. Sintaxa de definire a clasei 

Cea mai simplă formă de definire a clasei arată astfel:
class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>
Definițiile de clasă, cum ar fi definițiile funcțiilor ( declarațiile def ) trebuie executate înainte de a avea vreun efect. (Ați putea plasa o definiție de clasă într-o ramură a unei declarații if sau în interiorul unei funcții.)
În practică, afirmațiile din interiorul unei definiții de clasă vor fi, de obicei, definiții de funcții, dar alte declarații sunt permise și uneori utile - vom reveni la aceasta mai târziu. Definițiile funcțiilor dintr-o clasă au, în mod normal, o formă specifică de listă de argumente, dictată de convențiile de apel pentru metode - din nou, acest lucru este explicat mai târziu.
Când se introduce o definiție de clasă, se creează un nou spațiu de nume și se utilizează ca domeniu de aplicare local - astfel, toate asignările la variabilele locale intră în acest nou spațiu de nume. În particular, definițiile funcțiilor leagă numele aici pentru noua funcție.
Atunci când o definiție de clasă este lăsată în mod normal (prin capăt), se creează un obiect de clasă . Acesta este, în principiu, un înveliș în jurul conținutului spațiului de nume creat de definiția clasei; vom afla mai multe despre obiectele de clasă în secțiunea următoare. S-a restabilit domeniul original original (cel în vigoare imediat înainte de definirea clasei), iar obiectul de clasă este legat aici de numele clasei din antetul de clasă definit ( ClassName din exemplu).

9.3.2. Obiecte de clasă 

Elementele de clasă acceptă două tipuri de operațiuni: referințe atribute și instanțiere.
Referințele atributelor utilizează sintaxa standard folosită pentru toate referințele atributelor din Python: obj.name . Numele de atribute valide sunt toate numele care au fost în spațiul de nume al clasei atunci când a fost creat obiectul de clasă. Deci, dacă definiția clasei arăta astfel:
class MyClass:
    """A simple example class"""
    i = 12345
    def f(self):
        return 'hello world'
apoi MyClass.i și MyClass.f sunt referințe de atribute valide, returnând un întreg și un obiect de funcție, respectiv. De asemenea, pot fi atribuite atribute ale clasei, astfel încât să puteți schimba valoarea lui MyClass.i prin alocare. __doc__ este, de asemenea, un atribut valabil, returnând docstring aparținând clasei: "O clasă de exemple simple " .
Inițializarea clasei utilizează notația funcției. Doar pretindeți că obiectul de clasă este o funcție fără parametri care returnează o nouă instanță a clasei. De exemplu (presupunând clasa de mai sus):
x  =  MyClass ()
creează o nouă instanță a clasei și atribuie acest obiect variabilei locale x .
Operația de instanțiere ("apelarea" unui obiect de clasă) creează un obiect gol. Multe clase le place să creeze obiecte cu instanțe personalizate la o stare inițială specifică. Prin urmare, o clasă poate defini o metodă specială numită __init __ () , după cum urmează:
def __init__(self):
    self.data = []
Atunci când o clasă definește o metodă __init __ () , instanța de clasă invocă automat __init __ () pentru instanța de clasă nou creată. Astfel, în acest exemplu, o nouă instanță inițializată poate fi obținută prin:
x  =  MyClass ()
Desigur, metoda __init __ () poate avea argumente pentru o mai mare flexibilitate. În acest caz, argumentele date operatorului instanței de clasă sunt transmise __init __ () . De exemplu,
>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

9.3.3. Obiectele de instanță 

Acum, ce putem face cu obiectele instanței? Singurele operațiuni înțelese de obiectele instanței sunt referințele atributelor. Există două tipuri de nume de atribute valide, atribute și metode de date.
atributele de date corespund "variabilelor de instanță" din Smalltalk și "membrilor de date" din C ++. Atribuiile de date nu trebuie să fie declarate; cum ar fi variabilele locale, ele apar în momentul în care sunt atribuite pentru prima dată. De exemplu, dacă x este instanța MyClass creată mai sus, următoarea bucată de cod va tipări valoarea 16 , fără a lăsa o urmă:
x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print(x.counter)
del x.counter
Alt tip de referință a atributului de instanță este o metodă . O metodă este o funcție care "aparține" unui obiect. (În Python, metoda termenului nu este unică pentru instanțele de clasă: alte tipuri de obiecte pot avea și metode, de exemplu, obiectele din listă au metode numite adăugați, inserați, ștergeți, sortați și așa mai departe.În următoarea discuție, vom folosi metoda termenului exclusiv pentru a înțelege metode ale obiectelor instanțelor de clasă, cu excepția cazului în care se specifică altfel.)
Numele de metode valide ale unui obiect de instanță depind de clasa sa. Prin definiție, toate atributele unei clase care sunt obiecte funcționale definesc metodele corespunzătoare ale instanțelor sale. Deci, în exemplul nostru, xf este o referință validă a metodei, deoarece MyClass.f este o funcție, dar xinu este, deoarece MyClass.i nu este. Dar xf nu este același lucru cu MyClass.f - este un obiect de metodă , nu un obiect de funcție.

9.3.4. Metodă Obiecte 

De obicei, o metodă este chemată imediat după ce este obligată:
x . f ()
În exemplul MyClass , aceasta va returna șirul "hello world" . Cu toate acestea, nu este necesar să apelați imediat o metodă: xf este un obiect de metodă și poate fi stocat și apelat ulterior. De exemplu:
xf  =  x . f în 
timp ce  True : 
    print ( xf ())
va continua să tipărească lumea salutului până la sfârșitul timpului.
Ce se întâmplă exact atunci când se numește o metodă? Este posibil să fi observat că xf () a fost apelat fără un argument de mai sus, chiar dacă definiția funcției pentru f () a specificat un argument. Ce sa întâmplat cu argumentul? Cu siguranță, Python ridică o excepție atunci când o funcție care necesită un argument este numită fără nici un cuvânt - chiar dacă argumentul nu este utilizat efectiv ...
De fapt, poate ați ghicit răspunsul: lucrurile speciale despre metode sunt că obiectul este trecut ca primul argument al funcției. În exemplul nostru, apelul xf () este exact echivalent cu MyClass.f (x)În general, apelarea unei metode cu o listă de argumente n este echivalentă cu apelarea funcției corespunzătoare cu o listă de argumente care este creată prin introducerea obiectului metodei înaintea primului argument.
Dacă încă nu înțelegeți cum funcționează metodele, o privire la implementarea poate clarifica problemele. Atunci când un atribut instanță este referit, care nu este un atribut de date, se caută clasa sa. Dacă numele denumește un atribut de clasă valabil, care este un obiect funcțional, un obiect de metodă este creat prin împachetarea (indicii către) obiectul instanței și obiectul funcției care au fost găsiți împreună într-un obiect abstract: acesta este obiectul metodei. Atunci când obiectul metodei este numit cu o listă de argumente, se construiește o nouă listă de argumente din obiectul instanță și din lista de argumente, iar obiectul funcțional se numește cu această nouă listă de argumente.

9.4. Alegeri aleatorii 

Atributele de date suprascriu atributele metodei cu același nume; pentru a evita conflictele de nume accidentale, care pot provoca erori greu de găsit în programele mari, este înțelept să folosiți un fel de convenție care să minimizeze șansele de conflicte. Contractele posibile includ numele de metode de capitalizare, prefixarea numelor de atribute de date cu un șir unic mic (poate doar o subliniere) sau utilizarea verbelor pentru metode și substantive pentru atributele de date.
Atributele de date pot fi menționate prin metode, precum și de către utilizatorii obișnuiți ("clienți") ai unui obiect. Cu alte cuvinte, clasele nu sunt utilizabile pentru a pune în aplicare tipuri pure de date abstracte. De fapt, nimic din Python nu face posibilă ascunderea datelor ascunse - totul se bazează pe convenție. (Pe de altă parte, implementarea Python, scrisă în C, poate să ascundă complet detaliile implementării și să controleze accesul la un obiect, dacă este necesar, acesta putând fi folosit de extensiile Python scrise în C.)
Clienții ar trebui să folosească atributele de date cu grijă - clienții pot provoca daune invarianților întreținute de metode prin ștampilarea pe atributele lor de date. Rețineți că clienții pot adăuga propriile atribute de date unui obiect de instanță fără a afecta valabilitatea metodelor, atâta timp cât sunt evitate conflictele de nume - din nou, o convenție de numire poate salva o mulțime de dureri de cap aici.
Nu există o stenogramă pentru referirea atributelor de date (sau a altor metode!) Din cadrul metodelor. Consider că acest lucru mărește, de fapt, lizibilitatea metodelor: nu există nicio șansă de a confunda variabilele locale și variabilele de instanță atunci când se uită printr-o metodă.
Adesea, primul argument al unei metode se numește sine . Aceasta nu este altceva decât o convenție: numele de sine nu are absolut nici un înțeles special pentru Python. Rețineți însă că, prin nerespectarea convenției, codul dvs. poate fi mai puțin accesibil altor programatori Python și este de asemenea posibil ca un program de browser de clasă să poată fi scris care se bazează pe o astfel de convenție.
Orice obiect de funcții care este un atribut de clasă definește o metodă pentru instanțele acelei clase. Nu este necesar ca definiția funcției să fie inclusă în text în definiția clasei: atribuirea unui obiect funcțional unei variabile locale în clasă este, de asemenea, ok. De exemplu:
# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1
    def g(self):
        return 'hello world'
    h = g
Acum f , g și h sunt atribute ale clasei C care se referă la obiectele funcției și, prin urmare, toate metode ale instanțelor C - h sunt exact echivalente cu g . Rețineți că această practică servește, de obicei, doar la confuzarea cititorului unui program.
Metodele pot apela alte metode prin utilizarea atributelor metode ale argumentului auto :
class Bag:
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)

Metodele pot face referire la nume globale în același mod ca și funcțiile obișnuite. Domeniul de aplicare global asociat unei metode este modulul care conține definiția sa. (O clasă nu este niciodată utilizată ca domeniu de aplicare global). În timp ce unul rareori întâlnește un motiv bun pentru utilizarea datelor globale într-o metodă, există multe utilizări legitime ale domeniului global: pentru un singur lucru, funcțiile și modulele importate în sfera globală pot să fie utilizate prin metode, precum și funcții și clase definite în acesta. De obicei, clasa care conține metoda este ea însăși definită în acest domeniu global, iar în următoarea secțiune vom găsi câteva motive bune pentru care o metodă ar dori să se refere la propria clasă.
Fiecare valoare este un obiect și, prin urmare, are o clasă (de asemenea numită tipul ei ). Este stocat ca obiect .__ class__ .

9.5. Moștenire 

Bineînțeles, o caracteristică lingvistică nu ar fi demnă de denumirea "clasă" fără a susține moștenirea. Sintaxa pentru o definiție a clasei derivate arată astfel:
clasă  DerivedClassName ( BaseClassName ): 
    < declarație - 1 > 
    . 
    . 
    . 
    < declarație - N >
Numele BaseClassName trebuie definit într-un domeniu care conține definiția clasei derivate. În locul unui nume de clasă de bază, sunt permise și alte expresii arbitrare. Acest lucru poate fi util, de exemplu, atunci când clasa de bază este definită într-un alt modul:
Clasa de clasa  derivat˘a ( modname . BaseClassName ):
Executarea unei definiții de clasă derivată este aceeași ca și pentru o clasă de bază. Atunci când obiectul de clasă este construit, clasa de bază este amintită. Acesta este folosit pentru rezolvarea referințelor atributului: dacă un atribut solicitat nu este găsit în clasă, căutarea continuă să se uite în clasa de bază. Această regulă este aplicată recursiv dacă clasa de bază în sine este derivată dintr-o altă clasă.
Nu este nimic special în instanțierea claselor derivate: DerivedClassName () creează o nouă instanță a clasei. Referințele la metodă sunt rezolvate după cum urmează: se caută atributul de clasă corespunzător, coborând în jos lanțul de clase de bază, dacă este necesar, iar referința metodei este validă dacă aceasta dă un obiect de funcție.
Clasele derivate pot depasi metodele din clasele de baza ale acestora. Deoarece metodele nu au privilegii speciale atunci când apelați alte metode ale aceluiași obiect, o metodă a unei clase de bază care apelează o altă metodă definită în aceeași clasă de bază poate ajunge la a apela o metodă a unei clase derivate care o suprascrie. (Pentru programatori C ++: toate metodele din Python sunt efectiv virtuale .)
O metodă suprapusă într-o clasă derivată poate, de fapt, să dorească să se extindă mai degrabă decât să înlocuiască pur și simplu metoda de clasă de bază cu același nume. Există o modalitate simplă de a apela metoda directă a clasei de bază: trebuie doar să apelați BaseClassName.methodname (auto, argumente) . Acest lucru este uneori util și pentru clienți. (Rețineți că acest lucru funcționează numai dacă clasa de bază este accesibilă ca BaseClassName în domeniul global.)
Python are două funcții încorporate care funcționează cu moștenire:
  • Utilizați instanța () pentru a verifica tipul instanței: isinstance (obj, int) va fi Adevăratnumai dacă obj .__ class__ este int sau o anumită clasă derivată din int .
  • Utilizați issubclass () pentru a verifica moștenirea claselor: issubclass (bool, int) este True deoarece bool este o subclasă de int . Cu toate acestea, issubclass (float, int)este False, deoarece float nu este o subclasă de int .

9.5.1. Moștenire multiplă 

Python susține și o formă de moștenire multiplă. O definiție de clasă cu mai multe clase de bază arată astfel:
clasa  DerivedClassName ( Base1 ,  Base2 ,  Base3 ): 
    < declarație - 1 > 
    . 
    . 
    . 
    < declarație - N >
În cele mai multe scopuri, în cele mai simple cazuri, vă puteți gândi la căutarea atributelor moștenite de la o clasă părinte ca adâncime în primul rând, de la stânga la dreapta, fără a căuta de două ori în aceeași clasă în care există o suprapunere în ierarhie. Astfel, dacă un atribut nu este găsit în DerivedClassName , acesta este căutat în Base1 , apoi (recursiv) în clasele de bază ale Base1 și, dacă nu a fost găsit acolo, a fost căutat în Base2 și așa mai departe.
De fapt, este puțin mai complexă decât asta; ordinea de rezoluție a metodei se modifică dinamic pentru a sprijini apelurile de tip cooperativ către super () . Această abordare este cunoscută în alte limbi cu mai multe moșteniri ca metodă call-next și este mai puternică decât super-apelul găsit în limbi de mostenire singulară.
Comanda dinamică este necesară deoarece toate cazurile de moștenire multiplă prezintă una sau mai multe relații diamante (unde cel puțin una dintre clasele părinte poate fi accesată prin mai multe căi din clasa de jos). De exemplu, toate clasele moștenesc de la obiect , astfel încât orice caz de moștenire multiplă oferă mai mult de o cale pentru a ajunge la obiectPentru a păstra clasele de bază accesate de mai multe ori, algoritmul dinamic linearizează ordinea de căutare într-un mod care păstrează ordonarea de la stânga la dreapta specificată în fiecare clasă, care apelează fiecare părinte o singură dată și care este monotonică o clasă poate fi subclasată fără a afecta ordinea de prioritate a părinților săi). Luate împreună, aceste proprietăți fac posibilă proiectarea unor clase fiabile și extensibile cu moștenire multiplă. Pentru mai multe detalii, consultațihttp://www.python.org/download/releases/2.3/mro/ .

9.6. Variabile private 

Variabilele de instanță "private" care nu pot fi accesate decât în ​​interiorul unui obiect nu există în Python. Cu toate acestea, există o convenție care este urmată de majoritatea codului Python: un nume prefixat cu o subliniere (de exemplu, _spam ) trebuie tratat ca o parte non-publică a API-ului (indiferent dacă este o funcție, o metodă sau un membru de date) . Ar trebui să fie considerat un detaliu al implementării și să se schimbe fără notificare.
Deoarece există un caz de utilizare valabil pentru membrii de clasă privat (și anume pentru a evita ciocnirile de nume cu nume definite de subclase), există un sprijin limitat pentru un astfel de mecanism, denumit mangling nume . Orice identificator al formularului __spam (cel puțin două subliniere de frunte, cel mult un subliniere finală ) este înlocuit textual cu _classname__spam , unde classname este numele curent al clasei cu underscorele principale dezbatete . Acest mangling se face fără să se țină cont de poziția sintactică a identificatorului, atâta timp cât apare în definiția unei clase.
Numele mangling este util pentru a permite subclasele să înlocuiască metodele fără a rupe apelurile prin metoda intraclass. De exemplu:
Clasa de  cartografiere : 
    def  __init__ ( auto ,  iterable ): de 
        sine . items_list  =  [] 
        singur . __update ( iterabil )

    def  update ( auto ,  iterabil ): 
        pentru  element  în  iterabil : 
            auto . items_list . adăugați ( element )

    __update  =  actualizare    # copie privată a metodei original update ()

class  MappingSubclass ( Mapping ):

    def  actualizare ( auto ,  chei ,  valori ): 
        # furnizează o nouă semnătură pentru actualizare () 
        # dar nu rupe __init __ () 
        pentru  elementul  în  zip ( chei ,  valori ): 
            auto . items_list . adăugați ( element )
Rețineți că regulile de mangling sunt concepute în principal pentru a evita accidentele; este încă posibil să accesați sau să modificați o variabilă considerată privată. Acest lucru poate fi util chiar și în circumstanțe speciale, cum ar fi în programul de depanare.
Observați că codul trecut la exec () sau eval () nu consideră că clasa clasei invocate este clasa curentă; acest lucru este similar cu efectul instrucțiunii globale , efectul căruia este limitat la codul care este compilat împreună. Aceeași restricție se aplică și pentru getattr () , setattr () și delattr () , precum și atunci când se face referire directă __dict__ .

9.7. Cote și sfârșituri 

Uneori este util să aveți un tip de date similar cu "înregistrarea" Pascal sau C "struct", grupând împreună câteva elemente de date numite. O definiție a clasei goale va face bine:
clasa  angajat : 
    treci

john  =  Angajat ()  # Creați o înregistrare a angajatului gol

# Completați câmpurile 
john-ului de înregistrare . nume  =  'John Doe' 
john . dept  =  'computer lab' 
john . salariu  =  1000
O bucată de cod Python care așteaptă un anumit tip de date abstract poate fi adesea trecută de o clasă care emulează în schimb metodele acelui tip de date. De exemplu, dacă aveți o funcție care formatează anumite date dintr-un obiect de fișier, puteți defini o clasă cu metode read () și readline () care obțin datele dintr-un tampon șir și o transmit ca un argument.
Metoda instanței are și atribute: m .__ self__ este obiectul instanței cu metoda m () , iar m .__ func__ este obiectul funcției corespunzător metodei.

9.8. Excepțiile sunt prea 

Excepțiile definite de utilizator sunt identificate și pe clase. Folosind acest mecanism este posibil să se creeze ierarhii extensibile de excepții.
Există două noi forme valide (semantice) pentru instrucțiunea de creare :
ridica  clasa

ridicați  instanța
În prima formă, Clasa trebuie să fie o instanță de tip sau de o clasă derivată din ea. Prima formă este o stenogramă pentru:
ridica  Clasa ()
O clasă în afară de clauză este compatibilă cu o excepție în cazul în care este aceeași clasă sau o clasă de bază ale acestora (dar nu și invers - o clauză cu excepția listarea o clasă derivată nu este compatibilă cu o clasă de bază). De exemplu, următorul cod va imprima B, C, D în ordinea următoare:
clasa  B ( excepție ): 
    treceți 
clasa  C ( B ): 
    treceți 
clasa  D ( C ): 
    treceți

pentru  cls  în  [ B ,  C ,  D ]: 
    incercati : 
        ridica  cls () cu 
    excepția  D : 
        print ( "D" ) , cu 
    excepția  C : 
        print ( "C" ) cu 
    excepția  B : 
        print ( "B" )
Rețineți că dacă clauzele excepționale au fost inversate (cu excepția lui B în prealabil), ar fi imprimat B, B, B - prima potrivire cu excepția clauzei este declanșată.
Atunci când se imprimă un mesaj de eroare pentru o excepție nefolosită, este imprimat numele clasei excepției, apoi un colon și un spațiu și, în final, instanța a fost convertită la un șir folosind funcția built-in str () .

9.9. Iteratori 

Până acum ați observat probabil că majoritatea obiectelor container pot fi bucle cu ajutorul unei instrucțiuni pentru :
pentru  elementul  din  [ 1 ,  2 ,  3 ]: 
    print ( elementul ) 
pentru  elementul  din  ( 1 ,  2 ,  3 ): 
    print ( elementul ) 
pentru  cheie  în  { 'one' : 1 ,  'doi' : 2 }: 
    print ( cheie ) 
pentru  char  în  "123" : 
    print ( char ) 
pentru  linie în  deschis ( "myfile.txt" ): 
    print ( linie )
Acest stil de acces este clar, concis și convenabil. Utilizarea iteratoarelor pătrunde și unifică Python. În spatele scenei, instrucțiunea for solicită iter () pe obiectul containerului. Funcția returnează un obiect iterator care definește metoda __next __ () care accesează elementele din container unul câte unul. Atunci când nu mai există elemente, __next __ () ridică o excepție StopIteration, care indică faptul că buclă for va termina. Puteți apela metoda __next __ () folosind următoarea () funcție încorporată; acest exemplu arată cum funcționează toate:
>>>
in ? următorul ( it ) StopIteration  
  










    

După ce am văzut mecanica din spatele protocolului iterator, este ușor să adăugați comportamentul iterator la clasele tale. Definiți o metodă __iter __ () care returnează un obiect cu o metodă __next __ () . Dacă clasa definește __next __ () , atunci __iter __ () se poate întoarce singură :
clasa  inversă : 
    "" "Iterator pentru reluarea unei secvențe înapoi." " 
    def  __init__ ( sine ,  date ): 
        sine . date  =  date de 
        sine . index  =  len ( date ) 
    def  __iter__ ( auto ): 
        întoarcere  self 
    def  __next__ ( auto ): 
        dacă  ești singur . index  ==  0 : 
            ridicați  Auto StopIteration 
        . index =  de sine . index  -  1 
        întoarcerea de  sine . date [ auto . index ]
>>>
>>> rev  =  Reverse ( spam ) 
>>> iter ( rev ) 
<__ principal __ Obiect invers la 0x00A1DB50> 
>>> pentru  char  in  rev : 
...     print ( char ) 
... 
m 
a 
p 
s

9.10. Generatoare 

Generatoarele sunt un instrument simplu și puternic pentru crearea iteratorilor. Ele sunt scrise ca funcții obișnuite, dar utilizeazăinstrucțiunea de randament ori de câte ori doresc să returneze date. De fiecare dată cândse cheamă următorul () , generatorul revine la locul unde a rămas (își amintește toate valorile datelor și care a fost executată ultima dată). Un exemplu arată că generatoarele pot fi ușor de creat:
Definiție  inversă ( date ): 
    pentru  indexul  din  intervalul ( len ( date ) - 1 ,  - 1 ,  - 1 ): 
        date privind randamentul  [ index ]
>>>
>>> pentru  char  in  reverse ( 'golf' ): 
...     print ( char ) 
... 
f 
l 
o 
g
Orice lucru care se poate face cu generatoarele se poate face, de asemenea, cu iteratori de clasă, așa cum este descris în secțiunea anterioară. Ceea ce face generatoarele atât de compacte este că metodele __iter __ () și __next __ () sunt create automat.
O altă caracteristică cheie este aceea că variabilele locale și starea de execuție sunt salvate automat între apeluri. Acest lucru a făcut ca funcția să fie mai ușor de scris și mult mai clară decât o abordare utilizând variabile de exemplu, cum ar fi self.index și auto.data .
În plus față de crearea automată a metodei și de salvarea stării programului, atunci când generatoarele termină, ele cresc automat StopIteration . În combinație, aceste caracteristici ușurează crearea iteratorilor fără efort mai mult decât scrierea unei funcții obișnuite.

9.11. Expresii generatoare 

Unele generatoare simple pot fi codificate succint ca expresii utilizând o sintaxă similară înțelegerii listei, dar cu paranteze în loc de paranteze. Aceste expresii sunt concepute pentru situațiile în care generatorul este utilizat imediat printr-o funcție de închidere. Expresiile generatoare sunt mai compacte, dar mai puțin versatile decât definițiile complete ale generatoarelor și tind să fie mai prietenoase față de memorie decât comprehensiunea echivalentă a listelor.
Exemple:
>>>
>>> suma ( i * i  pentru  i  în  intervalul ( 10 ))                  # suma pătratelor 
285

>>> xvec  =  [ 10 ,  20 ,  30 ] 
>>> yvec  =  [ 7 ,  5 ,  3 ] 
>>> sum ( x * y  pentru  x , y  în  zip ( xvec ,  yvec ))          produs # dot 
260

>>> de la  importul de matematică  pi , sin >>> sine_table = { x : sin ( x * pi / 180 ) pentru x în intervalul ( 0 , 91 )}  
        

>>> unique_words  =  set ( cuvânt   pentru  linie  în  pagină   pentru  cuvânt  în  rândul . split ())

>>> valedictorian  =  max (( elev . APG ,  elev . Nume )  pentru  student de  la  absolvenți )

>>> data  =  'golf 
>> >> lista ( date [ i ]  pentru  i  în  intervalul ( len ( data ) - 1 ,  - 1 ,  - 1 )) 
[' f ',' g ']
Note de subsol
[1]Cu excepția unui singur lucru. Obiectele modulului au un atribut secret read-only numit__dict__ care returnează dicționarul utilizat pentru a implementa spațiul de nume al modulului; numele __dict__ este un atribut, dar nu un nume global. Evident, folosirea acestei metode încalcă abstractizarea implementării spațiului de nume și ar trebui să se limiteze la lucruri ca debuggerii post-mortem.




Sursa : https://docs.python.org/3.3/tutorial/classes.html



Niciun comentariu:

Trimiteți un comentariu