La rularea următorului cod, în care instrucțiunea for are o clauză else, ce se afișează?
for n in range(4): if n == 9: breakelse: print("done")print(n)
Se afișează doar 3, fără done
Se afișează doar done, fără 3
Se afișează, în această ordine, 3 și done
Se afișează, în această ordine, done și 3
Răspuns corectD. Se afișează, în această ordine, done și 3
Clauza else atașată unui for se execută atunci când bucla se termină fără a fi întreruptă cu break. range(4) nu conține 9, deci break nu apare niciodată, bucla parcurge tot intervalul, iar apoi print-ul din else rulează și afișează done. print(n) de după afișează ultima valoare rămasă în n după ieșirea din buclă, adică 3. Confundând ordinea, s-ar putea crede că 3 apare primul; interpretând greșit că else este mereu sărit la finalul buclei, s-ar ajunge la varianta fără done; ignorând faptul că n rămâne definit după buclă, s-ar ajunge la varianta fără 3.
Î2 | break și else
Se verifică modul în care este tratată clauza else atunci când se iese din buclă cu break. Care este rezultatul următorului cod?
for c in "abc": if c == "b": break print(c)else: print("no break")
Se afișează toate: a, b, c și no break
Se afișează, în această ordine, a și no break
Se afișează, în această ordine, a și b
Se afișează a, fără no break
Răspuns corectD. Se afișează a, fără no break
În prima trecere, c este a, deci print(c) rulează și afișează a. La a doua trecere, c devine b, iar break întrerupe bucla. Clauza else de la for se execută doar dacă bucla s-a terminat fără break, deci aici este sărită, iar no break nu apare. Dacă s-ar crede că else rulează întotdeauna la sfârșitul buclei, s-ar ajunge la varianta cu no break inclus; dacă s-ar interpreta greșit că print(c) se află înaintea lui break, s-ar ajunge la varianta care include și b; ignorând break-ul în sine, s-ar ajunge la varianta cu a, b, c toate afișate.
Î3 | else chiar și pentru gol
Se pune întrebarea ce se întâmplă cu clauza else a lui for atunci când obiectul iterat este gol. Care este rezultatul următorului cod?
items = []for it in items: print(it)else: print("finished")
Clauza else este ignorată și se produce TypeError
Deoarece are 0 iterații, se produce StopIteration
Nu se afișează nimic, iar bucla se termină
Se afișează o singură dată finished
Răspuns corectD. Se afișează o singură dată finished
Condiția pentru ca else de la for să se execute este „bucla s-a terminat fără break”, nu „s-a iterat cel puțin o dată”. items este gol, deci corpul buclei nu rulează niciodată, dar cum nici break nu a avut loc, else rulează oricum și afișează finished. Dacă s-ar crede că, fiind gol, else este și el sărit, s-ar ajunge la varianta fără afișare. A trece un for peste o listă goală este, în sine, o construcție corectă, deci nu produce excepție, iar TypeError sau StopIteration nu apar.
Î4 | while/else
Se atașează o clauză else unei instrucțiuni while și se ia în calcul cazul întreruperii cu break. Care este rezultatul următorului cod?
n = 5while n > 0: n -= 1 if n == 2: breakelse: print("loop ended")print(n)
Se afișează 0, fără loop ended
Se afișează 2, fără loop ended
Se afișează, în această ordine, loop ended și 2
Se afișează, în această ordine, loop ended și 0
Răspuns corectB. Se afișează 2, fără loop ended
n scade de la 5 cu câte 1, trecând prin 4 și 3, iar la 2 se produce break. Clauza else de la while, la fel ca la for, se execută doar dacă bucla se termină fără break, deci aici este sărită, iar loop ended nu apare. Rămâne doar print(n), care afișează 2. Dacă s-ar crede că else rulează întotdeauna, s-ar ajunge la varianta cu loop ended inclus; iar dacă s-ar interpreta greșit, ignorând break, că bucla continuă până când condiția devine falsă, s-ar ajunge la n egal cu 0.
Î5 | continue
Se combină continue și break într-o singură buclă în codul următor. Care este lista afișată la final?
out = []for i in range(6): if i == 3: continue if i == 5: break out.append(i)print(out)
[0, 1, 2, 4, 5]
[0, 1, 2, 3]
[0, 1, 2, 4]
[0, 1, 2, 3, 4]
Răspuns corectC. [0, 1, 2, 4]
Pentru i egal cu 0, 1, 2, ambele instrucțiuni if sunt trecute, iar valoarea este adăugată cu append. Pentru i egal cu 3, continue intervine, sărind restul acelei treceri, adică append-ul. Pentru i egal cu 4, append se execută din nou, iar pentru i egal cu 5, break întrerupe bucla, deci append nu mai are loc. Rezultă, prin urmare, [0, 1, 2, 4]. Dacă s-ar crede că se adaugă și trecerea în care apare break, s-ar ajunge la varianta care include și 5; dacă continue ar fi tratat ca pass, s-ar ajunge la varianta care include și 3.
Î6 | range invers
Se examinează șirul obținut la trecerea unui pas negativ către range. Care este rezultatul următorului cod?
print(list(range(10, 0, -3)))
[9, 6, 3, 0]
[7, 4, 1, -2]
[10, 7, 4, 1, 0]
[10, 7, 4, 1]
Răspuns corectD. [10, 7, 4, 1]
range(start, stop, step) pornește de la start, avansează cu step la fiecare pas și se oprește chiar înainte de a atinge stop. Aici, pornind de la 10 și scăzând câte 3, se obține 10, 7, 4, 1, iar valoarea următoare, -2, fiind sub sau egală cu 0, nu mai este inclusă. Deoarece stop, adică 0, nu este inclus, nu apare o formă în care 0 ar încheia șirul. Dacă s-ar crede greșit că start nu este inclus, s-ar ajunge la un șir care începe cu 7; dacă s-ar crede că numărătoarea începe cu o poziție înaintea lui start, s-ar ajunge la un șir care începe cu 9. Faptul că stop nu este inclus este identic cu cazul unui pas pozitiv.
Î7 | Tipul lui range
Care este descrierea potrivită pentru obiectul obținut apelând funcția predefinită range?
Un obiect de tip generator, care devine gol după o singură parcurgere
Un obiect de tip range, care devine listă dacă e trecut la list()
Un obiect de tip tuple, ale cărui elemente nu pot fi înlocuite
Un obiect de tip list, care se afișează direct cu paranteze pătrate
Răspuns corectB. Un obiect de tip range, care devine listă dacă e trecut la list()
range returnează un obiect de tip range, care calculează întregul necesar pe măsură ce este cerut. Nu ține în avans toate elementele, ca o listă, deci nu consumă multă memorie nici pentru intervale mari. Pentru a vedea conținutul înșiruit, se trece prin list(). type(range(3)) este range, nu list și nici tuple, iar afișat direct nu apare ca o secvență de elemente, ci ca range(0, 3). De asemenea, nu este de unică folosință, ci poate fi parcurs oricâte ori, deci nu este nici generator. De notat că faptul că poate fi accesat prin index și că elementele nu pot fi înlocuite este comun cu tuple, deci doar prin această proprietate nu se poate distinge de tuple.
Î8 | Evaluarea în scurtcircuit
Se verifică ce returnează operatorii logici or și and. Care este rezultatul următorului cod?
print([] or 0 or "z")print(1 and 0 and 2)
Se afișează, în această ordine, True și False
Se afișează, în această ordine, False și 0
Se afișează, în această ordine, z și 0
Se afișează, în această ordine, z și 2
Răspuns corectC. Se afișează, în această ordine, z și 0
or evaluează de la stânga la dreapta și returnează primul valoare care este considerată adevărată. Atât o listă goală, cât și 0, sunt considerate false, deci se returnează ultimul, "z". and, invers, returnează prima valoare considerată falsă: 1 este adevărat, iar la următorul, 0, se confirmă falsitatea și se returnează 0, fără a mai evalua 2 de la capătul din dreapta. Ceea ce se returnează nu este o valoare booleană, ci valoarea la care s-a oprit evaluarea, deci nu pot apărea True sau False. and returnează valoarea de la capătul din dreapta, 2, doar dacă toate valorile intermediare sunt adevărate.
Î9 | Comparații înlănțuite
La rularea următorului cod, care combină comparații înlănțuite și operatorul ternar, ce se afișează?
x = 3print(1 < x < 5)print("yes" if x % 2 else "no")
Se afișează, în această ordine, True și yes
Se afișează, în această ordine, True și no
Se afișează, în această ordine, False și no
Se afișează, în această ordine, False și yes
Răspuns corectA. Se afișează, în această ordine, True și yes
1 < x < 5 are aceeași semnificație ca (1 < x) and (x < 5); dacă x este 3, ambele condiții sunt îndeplinite, deci rezultatul este True. Operatorul ternar are forma valoare_dacă_adevărat if condiție else valoare_dacă_fals, iar condiția aici este x % 2, adică 1. În Python, orice întreg diferit de 0 este considerat adevărat, deci se alege yes. Dacă s-ar interpreta greșit comparația înlănțuită ca fiind asociată de la dreapta, ca în 1 < (x < 5), s-ar obține x < 5 egal cu True, adică 1, apoi 1 < 1 fiind False — un răspuns greșit. De asemenea, dacă 1 ar fi tratat ca fals, s-ar alege no.
Î10 | Rolul lui pass
Care este descrierea potrivită pentru instrucțiunea pass din Python?
Marchează întreruperea buclei propriu-zise și ieșirea din ea
Marchează faptul că, acolo unde sintactic este necesar un bloc, nu se face nimic
Marchează sărirea restului buclei și trecerea la iterația următoare
Marchează încheierea execuției funcției și returnarea unei valori către apelant
Răspuns corectB. Marchează faptul că, acolo unde sintactic este necesar un bloc, nu se face nimic
Python marchează blocurile prin indentare, deci nu se poate scrie un bloc gol. pass umple acel loc atunci când conținutul unei clase sau funcții urmează să fie scris ulterior, sau atunci când, la îndeplinirea unei condiții, se dorește intenționat să nu se facă nimic. Nu are niciun efect asupra fluxului de execuție. Trecerea la iterația următoare este continue, întreruperea buclei este break, iar returnarea unei valori către apelant este return — toate au un rol diferit de pass.
Î11 | enumerate
La rularea următorului cod, care trece un al doilea argument lui enumerate, ce apare pe ecran?
for i, name in enumerate(["gu", "choki", "pa"], 1): print(i, name)
Se afișează 3 linii: 1 gu / 2 choki / 3 pa
Se afișează 3 linii: 0 gu / 1 choki / 2 pa
Se afișează 3 linii: gu 1 / choki 2 / pa 3
Se afișează doar 2 linii: 1 gu / 2 choki
Răspuns corectA. Se afișează 3 linii: 1 gu / 2 choki / 3 pa
enumerate returnează, în ordine, tupluri (număr, element), iar al doilea argument, start, permite specificarea valorii de la care se începe numărătoarea. Aici s-a pasat 1, deci numerele sunt 1, 2, 3. Confundând cu numărătoarea implicită de la 0, atunci când start e omis, s-ar ajunge la o numărătoare începând cu 0. Tuplul returnat are numărul înaintea elementului, deci și ordinea din print(i, name) urmează aceeași secvență, iar numele nu apare niciodată primul. Toate cele 3 elemente sunt extrase, deci nu se oprește la 2 linii.
Î12 | Lungimea la zip
Se pasează lui zip două liste de lungimi diferite. Care este rezultatul următorului cod?
print(list(zip([1, 2, 3], [10, 20])))
[(1, 10), (2, 20)]
[(1, 10), (2, 20), (3,)]
[(1, 10), (2, 20), (3, 0)]
[(10, 1), (20, 2)]
Răspuns corectA. [(1, 10), (2, 20)]
zip extrage câte un element din fiecare obiect iterabil primit, îl grupează în tuplu, și se oprește imediat ce cel mai scurt dintre ele se epuizează. Aici a doua listă are 2 elemente, deci se formează doar 2 tupluri, iar valoarea rămasă, 3, este eliminată în tăcere, fără eroare. Nu se completează cu 0 și nici nu se creează un tuplu cu un singur element pentru rest. Conținutul tuplurilor urmează ordinea în care au fost pasate argumentele, deci nu apare o inversare precum 10 și 1.
Î13 | Descompunere cu zip
Datele grupate în tupluri sunt trecute din nou la zip, cu asterisc. Care este rezultatul următorului cod?
Răspuns corectB. Se afișează (1, 2, 3), apoi ('a', 'b', 'c')
Cu asterisc, fiecare tuplu din listă este pasat lui zip ca argument separat. Cu alte cuvinte, este echivalent cu a apela zip((1, 'a'), (2, 'b'), (3, 'c')), astfel încât primele elemente ale fiecărui tuplu se grupează între ele, la fel și cele de-a doua, rezultând (1, 2, 3) și ('a', 'b', 'c'), pe două rânduri. Este tehnica standard de a reveni la cele 2 liste inițiale, pornind de la datele grupate — aplicând zip de două ori se revine la forma originală. Rezultatul returnat este tuplu, nu listă, deci nu apare cu paranteze pătrate. Dacă se uită asteriscul și se scrie zip(pairs), tuplurile în sine sunt pasate ca un singur argument, rezultând tupluri cu un singur element, precum ((1, 'a'),).
Î14 | dict și zip
Se construiește un dicționar dintr-o listă de chei și una de valori. Care este rezultatul următorului cod?
zip(keys, vals) returnează, în ordine, tupluri (cheie, valoare), iar dict() primește această secvență de tupluri și construiește dicționarul. Primul element al tuplului devine cheie, iar al doilea valoare, deci numărul nu poate deveni cheie. Fiind trecut prin dict(), nu rămâne sub forma unei liste de tupluri. Chiar dacă afișarea folosește acolade, ceea ce e format prin perechi cu două puncte este dicționar, iar ceea ce arată doar valori înșiruite este mulțime (set).
Î15 | Comprehensiune de listă
La rularea următorului cod, care folosește o comprehensiune de listă, ce listă se afișează?
print([n * n for n in range(1, 5)])
[0, 1, 4, 9]
[2, 4, 6, 8]
[1, 4, 9, 16]
[1, 4, 9, 16, 25]
Răspuns corectC. [1, 4, 9, 16]
range(1, 5) returnează 1, 2, 3, 4; valoarea 5, specificată ca stop, nu este inclusă. Ridicând fiecare la pătrat, se obține 1, 4, 9, 16. Dacă s-ar crede greșit că range începe de la 0, s-ar ajunge la un șir care include 0; dacă s-ar crede greșit că stop este inclus, s-ar ajunge la un șir care include 25. Dacă n * n s-ar citi greșit ca n * 2, s-ar obține un șir care crește cu câte 2. Este util să se rețină că o comprehensiune evaluează expresia din stânga pentru fiecare element și creează o listă nouă cu rezultatele obținute.
Î16 | Comprehensiune de dicționar
Se execută o comprehensiune cu două puncte în interiorul acoladelor. Care este rezultatul următorului cod?
words = ["sun", "moon"]print({w: len(w) for w in words})
{'sun': 3, 'moon': 4}
[('sun', 3), ('moon', 4)]
{3: 'sun', 4: 'moon'}
{'sun', 'moon', 3, 4}
Răspuns corectA. {'sun': 3, 'moon': 4}
O comprehensiune cu două puncte în interiorul acoladelor este o comprehensiune de dicționar, în care partea stângă a celor două puncte devine cheie, iar cea dreaptă valoare. Aici se creează un dicționar în care cuvântul este cheie, iar numărul de litere valoare. Citind invers cheia și valoarea, s-ar ajunge la un dicționar în care numărul de litere este cheie. Cu paranteze pătrate ar rezulta o listă de tupluri, dar aici sunt acolade, deci nu se ajunge la acest rezultat. Fără două puncte, ar fi o comprehensiune de mulțime, care afișează doar valorile înșiruite, dar prezența celor două puncte face ca rezultatul să fie dicționar.
Î17 | Tipul obținut cu paranteze rotunde
O expresie de tip comprehensiune este cuprinsă în paranteze rotunde. Ce tip se afișează la rularea următorului cod?
g = (n for n in range(3))print(type(g))
<class 'range'>
<class 'list'>
<class 'generator'>
<class 'tuple'>
Răspuns corectC. <class 'generator'>
În Python nu există o comprehensiune de tuplu; forma cuprinsă în paranteze rotunde este o expresie generator. Tipul este generator, care nu creează toate valorile în avans, ci le calculează una câte una la cerere, economisind memorie, dar fiind un iterator, se epuizează după o singură utilizare. Dacă se dorește un tuplu, trebuie învelit cu tuple(). Scris cu paranteze pătrate, ar deveni o comprehensiune de listă, de tip list, iar dacă s-ar atribui direct range(3), ar rezulta tipul range. tuple nu se obține prin această construcție.
Î18 | Comprehensiune de mulțime
Se numără elementele obținute printr-o comprehensiune de mulțime. Care este rezultatul următorului cod?
print(len({n % 4 for n in range(10)}))
Se afișează 3
Se afișează 0
Se afișează 10
Se afișează 4
Răspuns corectD. Se afișează 4
Restul împărțirii fiecărei valori din range(10) la 4 este 0, 1, 2, 3, 0, 1, 2, 3, 0, 1. O comprehensiune cu acolade fără două puncte este o comprehensiune de mulțime, deci valorile duplicate se contopesc într-una singură, rămânând doar cele 4 valori distincte 0, 1, 2, 3. Dacă se ignoră faptul că duplicatele dispar și se numără direct valorile obținute, s-ar ajunge la 10. Dacă se ignoră faptul că 0 apare printre resturi și se numără doar 1, 2, 3 ca fiind 3 valori, se obține 3. 0 ar corespunde ideii greșite că o comprehensiune nu produce nimic, dar, câtă vreme se parcurge range(10), conținutul nu poate fi gol. Ordinea de afișare a unei mulțimi nu este determinată, deci cel mai sigur este să se verifice prin numărul de elemente.
Î19 | Comprehensiune dublă
Se pune întrebarea ordinea rezultată dintr-o comprehensiune cu două instrucțiuni for alăturate. Care este rezultatul următorului cod?
Atunci când o comprehensiune conține două instrucțiuni for alăturate, cea scrisă mai la stânga devine bucla exterioară. Ordinea este exact aceeași ca la instrucțiuni for obișnuite, imbricate: x rămâne fixat la 1 cât timp y parcurge a, b, apoi x devine 2 și se repetă aceeași parcurgere. Dacă s-ar citi greșit for-ul din dreapta ca fiind exterior, s-ar ajunge la o ordine în care x se schimbă mai întâi. Conținutul tuplului urmează ordinea (x, y) scrisă în expresie, deci litera nu poate apărea prima.
Î20 | Argumentul start
Care este descrierea potrivită pentru al doilea argument, start, al funcției predefinite enumerate?
Specifică numărul de la care se începe numărătoarea; dacă e omis, se numără de la 0
Specifică de la care element se începe extragerea; dacă e omis, se extrage de la început
Specifică din câte în câte se sare; dacă e omis, se avansează câte unul
Specifică până la al câtelea element se numără; dacă e omis, se numără până la capăt
Răspuns corectA. Specifică numărul de la care se începe numărătoarea; dacă e omis, se numără de la 0
Al doilea argument al lui enumerate, start, stabilește doar de la ce număr începe atribuirea numerelor. Valoarea implicită este 0, deci pasând 1 se obține o numerotare naturală, orientată spre oameni. Esențial este că se schimbă doar modul de numerotare, în timp ce intervalul și numărul elementelor extrase rămân neschimbate. Nu are rolul de a limita numărul de elemente sau de a sări peste unele, și nici de a deplasa poziția de la care începe extragerea — toate acestea sunt descrieri ale altor instrumente, precum feliile (slice).
Î21 | Valoarea returnată de sort
Valoarea returnată de metoda sort a unei liste este preluată într-o variabilă. Care este rezultatul următorului cod?
Se afișează, în această ordine, [3, 5, 9] și [3, 5, 9]
Se afișează, în această ordine, None și [5, 3, 9]
Se afișează, în această ordine, [3, 5, 9] și [5, 3, 9]
Se afișează, în această ordine, None și [3, 5, 9]
Răspuns corectD. Se afișează, în această ordine, None și [3, 5, 9]
sort este o metodă care sortează lista pe loc, iar valoarea returnată este None. Prin urmare, result primește None, iar rezultatul sortării rămâne în nums. Dacă s-ar crede că se returnează o listă nouă, sortată, s-ar ajunge la varianta în care result conține lista. Dacă se ignoră faptul că sort modifică lista originală, s-ar ajunge la varianta în care nums rămâne în ordinea inițială. Dacă se dorește o listă sortată, păstrând originalul neschimbat, se folosește funcția predefinită sorted.
Î22 | Diferența la sorted
Care este diferența corectă dintre metoda sort a unei liste și funcția predefinită sorted?
sort returnează o listă nouă, iar sorted sortează pe loc și returnează None
sort sortează pe loc și returnează None, iar sorted returnează o listă nouă
Ambele returnează o listă nouă, iar lista originală rămâne neschimbată în ambele cazuri
Ambele sortează pe loc și, în plus, returnează lista sortată
Răspuns corectB. sort sortează pe loc și returnează None, iar sorted returnează o listă nouă
sort este o metodă a listei, care sortează lista însăși și returnează None. sorted este o funcție predefinită, care returnează o listă nouă, sortată, fără să modifice deloc ordinea originală. Alegerea între ele depinde de dorința de a păstra sau nu originalul. Dacă rolurile celor două se învață inversat, s-ar ajunge la descrierea în care sort returnează o listă nouă. Dacă se presupune că ambele sunt fie distructive, fie nedistructive, s-ar ajunge la descrieri în care ambele sortează pe loc sau ambele păstrează originalul. De notat că sorted poate primi și alte obiecte iterabile, nu doar liste, iar rezultatul este întotdeauna o listă.
Î23 | Diferența la append
Se compară două metode de a adăuga o listă la o altă listă. Care este rezultatul următorului cod?
a = [1, 2]a.append([3, 4])b = [1, 2]b.extend([3, 4])print(a, b)
[1, 2, [3, 4]] [1, 2, [3, 4]]
[1, 2, 3, 4] [1, 2, [3, 4]]
[1, 2, 3, 4] [1, 2, 3, 4]
[1, 2, [3, 4]] [1, 2, 3, 4]
Răspuns corectD. [1, 2, [3, 4]] [1, 2, 3, 4]
append adaugă întregul argument ca un singur element la sfârșit, deci pasând o listă, aceasta devine imbricată, iar lungimea crește cu 1. extend extrage prin iterare valorile argumentului și le adaugă una câte una, deci conținutul se desface, iar lungimea crește cu 2. Dacă se inversează rolurile celor două, rezultatele pentru a și b se inversează. Dacă se crede că ambele au același efect, se ajunge fie la ambele imbricate, fie la ambele aplatizate. Merită reținut și faptul că valoarea returnată de ambele metode este None, deci nu trebuie preluat rezultatul într-o variabilă.
Î24 | Copie superficială
O listă imbricată este duplicată printr-o felie (slice), iar interiorul ei este modificat. Care este rezultatul următorului cod?
Duplicarea printr-o felie este o copie superficială: lista exterioară este creată din nou, dar elementele conținute în ea rămân aceleași cu cele din original, fiind partajate. copy1[0] și orig[0] indică aceeași listă, deci un append acolo se vede și în partea originalului. Dacă s-ar crede că separarea este completă, s-ar ajunge la varianta în care originalul rămâne neschimbat. Cum s-a modificat doar prima listă interioară, modificarea nu se extinde la elementele de după, iar cum nu s-a adăugat la nivelul exterior, 9 nu ajunge să apară alături în lista exterioară. Pentru a separa și interiorul, se folosește copy.deepcopy.
Î25 | Copie profundă
Se compară copia profundă și copia superficială într-un singur cod. Ce devine base după execuție?
copy.deepcopy duplică și conținutul imbricat, deci d[0] devine o listă diferită de base[0], iar un append acolo nu ajunge la base. Pe de altă parte, s este o copie superficială, deci s[1] și base[1] sunt aceeași listă, iar un append acolo se vede și în base. Prin urmare, doar elementul de la coadă crește. Dacă s-ar crede că ambele modificări ajung la base, ar crește ambele elemente interioare; dacă s-ar crede că niciuna nu ajunge, base ar rămâne neschimbat. Dacă se confundă copia profundă cu cea superficială, ar crește doar primul element.
Î26 | Capcana înmulțirii
S-a încercat construirea unui tabel bidimensional prin înmulțirea unei liste. Care este rezultatul următorului cod?
grid = [[0] * 3] * 2grid[0][1] = 5print(grid)
[[0, 0, 0], [0, 5, 0]]
[[5, 0, 0], [5, 0, 0]]
[[0, 5, 0], [0, 0, 0]]
[[0, 5, 0], [0, 5, 0]]
Răspuns corectD. [[0, 5, 0], [0, 5, 0]]
Înmulțirea exterioară nu creează rânduri noi, ci doar așază alături două referințe către aceeași listă. grid[0] și grid[1] sunt aceeași entitate, deci modificarea poziției de index 1 într-una dintre ele apare, la fel, în cealaltă. Dacă s-ar crede că rândurile sunt independente, s-ar ajunge la varianta în care se schimbă doar unul dintre rânduri. Cum modificarea a fost făcută la poziția de index 1, nu rezultă nici varianta în care primul element devine 5. Pentru a face rândurile independente, se scrie [[0] * 3 for _ in range(2)].
Î27 | Tuplu cu un singur element
Se compară tipul unei valori doar încadrate în paranteze rotunde cu cel al unei valori urmate de o virgulă. Care este rezultatul următorului cod?
x = (7)y = (7,)print(type(x).__name__, type(y).__name__)
Se afișează, în această ordine, int și int
Se afișează, în această ordine, tuple și tuple
Se afișează, în această ordine, tuple și int
Se afișează, în această ordine, int și tuple
Răspuns corectD. Se afișează, în această ordine, int și tuple
Ceea ce definește un tuplu nu sunt parantezele rotunde, ci virgula. (7) este doar un întreg încadrat de paranteze pentru a marca ordinea operațiilor, deci tipul este int; abia (7,), cu virgulă la sfârșit, devine un tuplu cu un singur element. Dacă s-ar crede că orice încadrare cu paranteze rotunde produce un tuplu, ambele ar deveni tuple. Dacă cele două se confundă, s-ar obține fie ordinea inversată, fie ambele ca int. De notat că singura excepție este tuplul gol, care se scrie () fără virgulă.
Î28 | Conținutul unui tuplu
S-a încercat adăugarea unui element la o listă aflată în interiorul unui tuplu. Care este rezultatul următorului cod?
t = (1, [2, 3], 4)t[1].append(5)print(t)
Se produce TypeError
(1, [2, 3], 4, 5)
(1, [2, 3, 5], 4)
(1, [2, 3], 4)
Răspuns corectC. (1, [2, 3, 5], 4)
Ceea ce este imuabil (înghețat) la un tuplu este corespondența dintre poziții și obiecte, nu conținutul obiectelor la care se face referire. t[1] este o listă, iar acea listă în sine este mutabilă, deci se poate face append pe ea. O scriere de tipul t[1] = [], care înlocuiește direct elementul tuplului, ar produce TypeError, dar aici nu se înlocuiește niciun element. Cum adăugarea a avut loc în interiorul listei, nici lungimea tuplului nu crește, nici nu rămâne complet neschimbată.
Î29 | Atribuire pe felie
Se atribuie unei felii dintr-o listă o listă de lungime diferită. Care este rezultatul următorului cod?
x = [1, 2, 3, 4, 5]x[1:3] = [9]print(x)
[1, 9, 4, 5]
[1, 9, 3, 4, 5]
[1, 9, 9, 4, 5]
[1, 2, 9, 4, 5]
Răspuns corectA. [1, 9, 4, 5]
Atribuirea către o felie este operația de a înlocui complet intervalul specificat cu conținutul din partea dreaptă. x[1:3] indică cele 2 elemente 2 și 3, care sunt înlocuite cu un singur element, 9, deci lungimea totală scade de la 5 la 4. Dacă s-ar crede că se înlocuiește doar un singur element, lungimea ar rămâne 5; dacă s-ar crede că partea dreaptă se extinde la lățimea intervalului, ar apărea două valori de 9 alăturate. Dacă începutul intervalului este citit greșit, decalat cu o poziție, ar rămâne valoarea 2. Caracteristica atribuirii pe felie este tocmai faptul că lățimea din stânga și lungimea din dreapta pot diferi.
Î30 | Inserare și ștergere
Se face, în continuare, o atribuire către o felie de lățime 0 și apoi un del. Care este rezultatul următorului cod?
y = [1, 2, 3]y[1:1] = [7, 8]del y[0]print(y)
[7, 8, 3]
[1, 7, 8, 3]
[7, 8, 2, 3]
[2, 3, 7, 8]
Răspuns corectC. [7, 8, 2, 3]
y[1:1] este un interval de lățime 0, deci atribuirea acolo devine o inserare fără ștergere, iar lista devine [1, 7, 8, 2, 3]. del y[0] care urmează elimină primul element, 1, deci rămâne [7, 8, 2, 3]. Dacă s-ar crede că, la inserare, dispare și un element original, s-ar ajunge la forma 7 8 3; dacă s-ar crede că del șterge o altă poziție, ar rămâne primul element, 1. Dacă s-ar interpreta greșit ca adăugare la sfârșit, 2 și 3 ar apărea la început. De notat că del este o instrucțiune, fără valoare returnată, și șterge fără să extragă valoarea.
Î31 | Valoarea implicită la get
S-a interogat cu get o cheie inexistentă într-un dicționar. Care este conținutul afișat la rularea următorului cod?
d = {"a": 1, "b": 2}print(d.get("z"), d.get("z", 0))
Se afișează, în această ordine, None și 0
La prima interogare se produce KeyError
Se afișează, în această ordine, None și None
Se afișează, în această ordine, 0 și 0
Răspuns corectA. Se afișează, în această ordine, None și 0
get nu lansează excepție atunci când cheia lipsește; dacă al doilea argument este omis, returnează None, iar dacă este dat, returnează acea valoare. Prin urmare, prima interogare dă None, iar a doua dă 0. Dacă s-ar crede că, fără al doilea argument, tot 0 se returnează, ambele ar deveni 0; dacă s-ar crede că al doilea argument este ignorat, ambele ar deveni None. Scris cu paranteze pătrate, d["z"], ar produce KeyError, iar get este instrumentul menit să evite exact acest lucru.
Î32 | setdefault
setdefault este apelat atât pentru o cheie deja existentă, cât și pentru una inexistentă. Care este rezultatul următorului cod?
d = {"a": 1}print(d.setdefault("a", 99))print(d.setdefault("b", 99))print(d)
Se afișează 99 și 99, apoi {'a': 99, 'b': 99}
Se afișează 1 și 99, apoi {'a': 1, 'b': 99}
Se afișează 1 și None, apoi {'a': 1, 'b': None}
Se afișează 1 și 99, apoi {'a': 1}
Răspuns corectB. Se afișează 1 și 99, apoi {'a': 1, 'b': 99}
setdefault, dacă cheia există, doar returnează valoarea deja existentă, fără să modifice dicționarul. Dacă cheia nu există, inserează al doilea argument ca valoare și returnează acea valoare. Astfel, la prima apelare se returnează valoarea existentă, 1, iar dicționarul rămâne neschimbat; la a doua, se inserează 99, care este și returnat. Dacă s-ar crede că se suprascrie și valoarea existentă, ambele ar deveni 99; dacă s-ar crede că inserarea nu are loc, dicționarul nu ar crește. Dacă al doilea argument este omis, valoarea inserată devine None, deci varianta cu None corespunde cazului în care al doilea argument nu a fost scris.
Î33 | Ce verifică in
Se verifică ce anume examinează operatorul in aplicat unui dicționar. Care este rezultatul următorului cod?
d = {"x": 1, "y": 2}print("x" in d, 1 in d, 1 in d.values())
Se afișează, în această ordine, True False True
Se afișează, în această ordine, True True True
Se afișează, în această ordine, True False False
Se afișează, în această ordine, False True True
Răspuns corectA. Se afișează, în această ordine, True False True
Operatorul in aplicat unui dicționar examinează doar cheile. "x" există ca și cheie, deci rezultă True; 1 există ca valoare, dar nu ca și cheie, deci rezultă False. Dacă se dorește verificarea valorilor, se aplică pe d.values(), unde rezultatul este True. Dacă s-ar crede că in examinează și valorile, toate ar deveni True; dacă s-ar crede că nici values() nu găsește valorile, ultima ar deveni False. Dacă rolurile cheii și valorii se inversează la citire, prima ar deveni False. Practica standard este să se verifice mai întâi prezența cheii, iar apoi să se extragă valoarea cu paranteze pătrate.
Î34 | Duplicarea unei chei
Aceeași cheie a fost scrisă de două ori într-un literal de dicționar. Care este rezultatul următorului cod?
d = {"a": 1, "b": 2, "a": 3}print(d)
{'a': 3, 'b': 2}
{'a': 1, 'b': 2}
{'b': 2, 'a': 3}
{'a': 3, 'b': 3}
Răspuns corectA. {'a': 3, 'b': 2}
Un literal de dicționar creează elementele în ordine, de la stânga la dreapta, deci dacă aceeași cheie apare de două ori, ultima valoare o suprascrie pe prima. Nu apare nicio eroare sau avertizare. Dacă s-ar crede că rămâne prima valoare scrisă, valoarea lui a ar rămâne 1. De asemenea, dicționarul păstrează ordinea inserării, iar suprascrierea nu schimbă poziția, deci a rămâne primul în ordine. Prin urmare, nici ordinea cheilor nu se inversează, nici valoarea lui b nu este afectată.
Î35 | Modul de a construi un dicționar
Se compară un dicționar construit din argumente cu nume și unul construit dintr-o secvență de perechi. Care este rezultatul următorului cod?
Răspuns corectC. Se afișează True, apoi {'x': 1, 'y': 2}
dict poate construi un dicționar atât din argumente cu nume, cât și dintr-o secvență de perechi (cheie, valoare). Ambele forme de scriere produc un dicționar cu același conținut, deci comparația dă True. Dacă s-ar crede că moduri diferite de construcție produc obiecte diferite, comparația ar da False. Numele argumentului cu nume devine direct șirul de caractere al cheii, deci cheia și valoarea nu se inversează. Odată trecut prin dict, rezultatul este deja un dicționar, deci nu rămâne sub forma unei secvențe de perechi.
Î36 | Acolade goale
Se compară tipul acoladelor goale cu tipul lui set(). Care sunt cele două nume de tip afișate la rularea următorului cod?
a = {}b = set()print(type(a).__name__, type(b).__name__)
Se afișează, în această ordine, dict și dict
Se afișează, în această ordine, set și set
Se afișează, în această ordine, dict și set
Se afișează, în această ordine, set și dict
Răspuns corectC. Se afișează, în această ordine, dict și set
{1, 2}, cu elemente înăuntru, devine mulțime (set), dar dacă interiorul e gol, nu se poate determina dacă e vorba de dicționar sau mulțime. Python tratează acest caz ca dicționar, deci {} este un dicționar gol. Pentru o mulțime goală, singura variantă este set(). Dacă s-ar crede că acoladele înseamnă întotdeauna mulțime, ambele ar deveni set; dacă cele două se confundă, ordinea se inversează. Dacă s-ar crede că și set() devine dicționar, ambele ar deveni dict. Cum atât mulțimile, cât și dicționarele folosesc acolade, această distincție se confundă ușor.
Î37 | Operații pe mulțimi
S-au aplicat operațiile de intersecție și diferență simetrică la două mulțimi. Care este rezultatul următorului cod?
Se afișează, în această ordine, [3, 4] și [1, 2, 3, 4, 5]
Se afișează, în această ordine, [1, 2, 5] și [3, 4]
Se afișează, în această ordine, [3, 4] și [1, 2]
Se afișează, în această ordine, [3, 4] și [1, 2, 5]
Răspuns corectD. Se afișează, în această ordine, [3, 4] și [1, 2, 5]
Simbolul & (ampersand) este intersecția, deci rămân 3 și 4, care sunt în ambele. Simbolul ^ (accent circumflex) este diferența simetrică, care adună elementele prezente doar într-una dintre cele două, deci rămân 1 și 2, prezente doar în s1, și 5, prezent doar în s2, iar 3 și 4, comune, dispar. Dacă diferența simetrică se confundă cu diferența simplă, ar lipsi 5; dacă cele două operații se inversează, ordinea rezultatelor s-ar inversa. Dacă diferența simetrică se confundă cu reuniunea, ar include și 3 și 4. Cum ordinea de afișare a unei mulțimi nu este determinată, aici se folosește sorted pentru verificare.
Î38 | Eliminarea duplicatelor
O listă cu duplicate este trecută printr-o mulțime. Care este rezultatul afișat la rularea următorului cod?
data = [3, 1, 3, 2, 1, 1]print(len(set(data)), sorted(set(data)))
Se afișează, în această ordine, 6 și [3, 1, 3, 2, 1, 1]
Se afișează, în această ordine, 6 și [1, 2, 3]
Se afișează, în această ordine, 3 și [3, 1, 2]
Se afișează, în această ordine, 3 și [1, 2, 3]
Răspuns corectD. Se afișează, în această ordine, 3 și [1, 2, 3]
Pasând o listă lui set, duplicatele sunt eliminate, rămânând doar cele 3 valori distincte 1, 2, 3, deci lungimea este 3. Pasând o mulțime lui sorted, se returnează o listă nouă, ordonată crescător. Dacă s-ar crede că duplicatele rămân, numărul ar deveni 6. sorted ordonează după mărime, nu după ordinea de apariție originală, deci rezultatul nu urmează ordinea în care au apărut prima dată elementele. Ordinea de afișare a unei mulțimi în sine nu are semnificație, deci pentru a obține o ordine se trece prin sorted.
Î39 | Condiția elementelor
S-a încercat adăugarea, pe rând, a unui tuplu și a unei liste într-o mulțime. Ce se întâmplă la rularea următorului cod?
s = set()s.add((1, 2))s.add([3, 4])print(len(s))
Se afișează 1, iar lista este convertită la tuplu
Se produce TypeError, deoarece o listă nu poate fi pusă într-o mulțime
Se produce ValueError, deoarece tipurile de elemente nu se pot amesteca
Se afișează 2, iar ambele elemente ajung în mulțime
Răspuns corectB. Se produce TypeError, deoarece o listă nu poate fi pusă într-o mulțime
Elementele unei mulțimi și cheile unui dicționar trebuie să fie hashabile. Un tuplu, neputând fi modificat pe interior, este hashabil și poate fi adăugat, dar o listă, al cărei conținut se poate schimba ulterior, nu este hashabilă, ceea ce produce TypeError, cu mesajul unhashable type. Dacă s-ar crede că ambele se adaugă, s-ar afișa 2; dacă s-ar crede că lista se convertește implicit la tuplu, s-ar afișa 1. Amestecarea tipurilor în sine nu este o problemă, deci și explicația bazată pe ValueError este greșită.
Î40 | Cele trei extrageri
Care este combinația corectă privind ce returnează metodele keys, values și items ale unui dicționar?
keys returnează perechi de valori, values returnează perechi de chei, items returnează numărul de elemente
keys returnează doar cheile, values doar valorile, iar items returnează, în ordine, tupluri (cheie, valoare). Forma standard pentru a parcurge un dicționar este for k, v in d.items(), preluând cele două variabile deodată. Dacă rolurile celor trei se rețin inversat, se ajunge la descrieri precum keys returnând valorile. Ceea ce returnează items este o secvență de elemente, nu numărul lor, deci și descrierea „returnează numărul de elemente” e greșită — pentru număr se folosește len. De notat că, pasat direct unui for, un dicționar extrage cheile.
Exersare: rezolvați întrebările de pe această pagină
Acesta este un instrument de exersare cu întrebări în ordine aleatorie (funcționează când JavaScript este activat). Puteți citi oricum toate întrebările și explicațiile de mai sus.
* Explicațiile sunt informații în scop de studiu. Tematica și sistemul examenelor se schimbă de la an la an, așa că verificați întotdeauna anunțurile oficiale ale organizatorului examenului.
Această pagină este o traducere a textului original în japoneză. Dacă traducerea diferă de original, prevalează versiunea în japoneză. Vedeți originalul în japoneză