Sari la conținut
← Python de la zero
Progres curs 0 / 7 lecții (0%)

Tipuri și operatori

Lectură estimată: 14 minute

Estimare pentru text, la un ritm de 180 de cuvinte pe minut. Timpul pentru analizarea codului, exerciții și proiecte se adaugă separat și depinde de ritmul tău.

Aceeași valoare afișată poate însemna lucruri diferite

Într-un tabel de comenzi, celula care arată 12 poate reprezenta o cantitate, un identificator sau un text introdus de utilizator. Programul nu poate ghici sensul doar din aspect. Dacă tratezi identificatorul 0012 ca număr, pierzi zerourile inițiale. Dacă tratezi cantitatea ca text, adunarea poate deveni concatenare. Alegerea tipului de date face parte din rezolvarea problemei, înaintea formulei.

În această lecție construim un calcul demonstrativ pentru materiale de atelier: un număr de caiete la un preț unitar și o reducere explicită. Vom separa textul primit, valorile validate, calculul și mesajul afișat. Prețurile și procentele sunt fictive; exemplul nu include TVA și nu încearcă să implementeze reguli contabile. Scopul este să observi exact când o valoare este acceptată și ce înseamnă rezultatul.

La final vei putea explica de ce "12" + "3" produce alt rezultat decât 12 + 3, de ce zero nu înseamnă automat lipsă și de ce afișarea cu două zecimale nu repară orice calcul. Vei avea și un script mic care respinge intrări neacceptate, în loc să le transforme pe ascuns în numere aparent utile.

Nume, obiecte și tipuri

O atribuire precum cantitate = 3 asociază numele cantitate cu un obiect întreg. Nu declarăm un sertar care poate ține numai întregi pentru totdeauna. Putem reasocia ulterior același nume cu alt obiect, dar asta nu înseamnă că este o idee bună să schimbăm sensul lui de la număr la mesaj. Numele clare și sensul stabil fac programul mai ușor de urmărit.

Tipurile de bază pe care le folosim sunt int pentru întregi, float pentru numere în virgulă mobilă, str pentru text, bool pentru adevărat sau fals și valoarea None pentru absență explicită. Funcția type îți arată tipul unui obiect. În timpul învățării, afișarea tipului lângă valoare este un instrument de diagnostic, mai ales când datele vin din input sau din fișiere.

cantitate = 3
cod = "003"
pret_aproximativ = 12.5
confirmat = False
observatie = None

print(type(cantitate).__name__, cantitate)
print(type(cod).__name__, cod)
print(type(pret_aproximativ).__name__, pret_aproximativ)
print(type(confirmat).__name__, confirmat)
print(type(observatie).__name__, observatie)

Rezultatele pentru numele tipurilor sunt int, str, float, bool și NoneType, în această ordine. Codul 003 rămâne text, tocmai pentru a păstra reprezentarea identificatorului. Nu avem de făcut operații aritmetice cu acel cod. Cantitatea trei, în schimb, participă la înmulțiri. Două valori se pot referi la aceeași realitate comercială și totuși să aibă roluri tehnice diferite.

Într-un program mai mare, întrebarea bună nu este doar ce tip are acum valoarea, ci ce tip promite intrarea. Un formular poate trimite cantitatea ca text. Responsabilitatea noastră este să verificăm și să convertim acel text la granița programului, apoi să lucrăm cu un întreg. Dacă amestecăm verificarea cu afișarea în multe locuri, ajungem ușor la reguli contradictorii.

Operatorul depinde de operanzi

Semnul plus adună numere, dar concatenează șiruri. Înmulțirea poate înmulți numere sau repeta un șir. Aceste comportamente sunt utile atunci când sunt intenționate și surprinzătoare când ai uitat că intrarea este text. Rulează exemplele și prezice fiecare rezultat înainte să privești ieșirea.

print(12 + 3)
print("12" + "3")
print("ab" * 3)
print(int("12") + 3)
print(7 / 2)
print(7 // 2)
print(7 % 2)

Rezultatele sunt 15, 123, ababab, 15, 3.5, 3 și 1. Primele două linii explică de ce o sumă dintr-un formular poate ieși greșit fără să producă o excepție. Operația este validă pentru șiruri; intenția noastră era alta. Un program care nu afișează erori nu este neapărat corect.

Împărțirea / și împărțirea întreagă // au contracte diferite. Pentru numere negative, // rotunjește rezultatul în jos: -7 // 2 este -4. Nu o descrie ca simplă ștergere a zecimalelor. Restul % poate fi folosit pentru a verifica dacă o cantitate se împarte exact în pachete, dar sensul trebuie legat de problemă. Pentru șapte obiecte în pachete de două, obții trei pachete complete și un obiect rămas.

Ordinea operațiilor contează. În calculul (pret * cantitate) - reducere, parantezele fac intenția vizibilă, chiar dacă înmulțirea ar avea oricum prioritate. Preferă să introduci nume intermediare când formula devine greu de citit. subtotal și economie sunt mai ușor de verificat separat decât o expresie lungă care îmbină conversii, reduceri și formatare.

Conversia nu este întreaga validare

input returnează text. int poate transforma un șir acceptat într-un întreg, dar nu știe dacă în aplicația ta sunt permise cantități negative sau foarte mari. int("3") produce trei, iar int("3.5") ridică ValueError. int(3.9) produce trei prin trunchiere spre zero; această operație nu reprezintă validarea unei cantități întregi primite ca text.

Pentru atelier stabilim următoarea regulă: cantitatea este scrisă numai cu cifrele ASCII de la zero la nouă, are cel mult trei caractere și reprezintă un număr între 1 și 100. Eliminăm spațiile exterioare înainte de verificare. Acceptăm 003 drept cantitate trei, dar nu folosim această regulă pentru identificatoare. Respingem +3, 3.0 și 3e1, chiar dacă alte parsere ar putea interpreta unele forme.

Alegerea unei gramatici restrânse face laboratorul previzibil. Nu susținem că aceasta este singura interfață corectă. Un produs pentru public larg poate permite alte formate, dar trebuie să spună care sunt și să le testeze. Nu modifica textul în tăcere eliminând toate semnele: din -3 nu trebuie să obții 3 printr-o curățare agresivă.

text = " 003 ".strip()
if not (1 <= len(text) <= 3):
    raise SystemExit("Cantitatea trebuie să aibă 1-3 cifre.")
if any(caracter not in "0123456789" for caracter in text):
    raise SystemExit("Folosește numai cifre de la 0 la 9.")
cantitate = int(text)
if not 1 <= cantitate <= 100:
    raise SystemExit("Cantitatea trebuie să fie între 1 și 100.")
print(cantitate)

any răspunde dacă măcar un caracter nu aparține alfabetului permis. Nu trebuie să memorezi acum toate formele de expresii generatoare; urmărește întrebarea formulată de condiție. Ordinea verificărilor este importantă: întâi forma textului, apoi conversia, apoi limita numerică. Pentru intrarea de mai sus, programul afișează 3. Pentru 000, forma este acceptată, dar regula cantității respinge zero.

Zero, False și None nu sunt același lucru

Într-un test condițional, mai multe valori sunt considerate false: zero, șirul gol, False și None, printre altele. Acest lucru este convenabil pentru unele verificări, dar periculos când valoarea zero are sens. Dacă un preț promoțional poate fi zero, o condiție if not pret îl confundă cu lipsa prețului.

Folosim None pentru o valoare încă necunoscută și verificăm explicit pret is None. Folosim o comparație numerică atunci când întrebarea este dacă prețul este negativ. Folosim un bool atunci când exprimăm o decizie cu două stări. Nu lăsa aceeași variabilă să reprezinte pe rând lipsa, eroarea și valoarea validă fără un contract clar.

pret = 0
print(pret is None)
print(pret == 0)
print(bool("False"))
print(bool(""))
print(True == 1)
print(type(True) is int)

Rezultatele sunt False, True, True, False, True și False. Șirul "False" nu este gol, deci conversia lui la bool produce True. Dacă citești o opțiune textuală da/nu, trebuie să o interpretezi după valorile permise, nu să apelezi pur și simplu bool. Ultimele două linii arată o particularitate importantă: valorile booleene au o relație numerică cu întregii, dar nu trebuie acceptate automat ca o cantitate într-un contract strict.

Pentru comparații obișnuite folosește ==. Pentru verificarea absenței folosește is None. Operatorul is verifică identitatea obiectelor, nu egalitatea generală a valorilor. Evită experimente precum numar is 3 pentru a decide dacă două numere sunt egale; unele optimizări ale interpretorului pot crea impresii înșelătoare în exemple foarte mici.

Numere aproximative și calcule zecimale

float este potrivit pentru multe măsurători și calcule în care aproximația este acceptată. Unele fracții zecimale nu au o reprezentare binară finită. De aceea, o expresie precum 0.1 + 0.2 poate să nu fie exact egală cu 0.3. Afișarea cu două zecimale controlează prezentarea rezultatului, fără să schimbe retroactiv valorile folosite în calcul.

Pentru exemplul monetar folosim Decimal creat din text. Păstrăm o regulă explicită de rotunjire și verificăm că valorile sunt finite. Decimal poate reprezenta și valori speciale, precum NaN sau Infinity, deci faptul că o conversie a reușit nu dovedește singur că avem un preț acceptabil. Pentru această lecție evităm asemenea intrări printr-o gramatică restrânsă și o verificare suplimentară.

from decimal import Decimal, ROUND_HALF_UP

pret = Decimal("12.50")
cantitate = 3
procent = Decimal("10")
subtotal = pret * cantitate
economie = (subtotal * procent / Decimal("100")).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)
total = subtotal - economie
print(f"Subtotal: {subtotal:.2f}")
print(f"Economie: {economie:.2f}")
print(f"Total: {total:.2f}")

Obții subtotalul 37.50, economia 3.75 și totalul 33.75. Politica laboratorului este să rotunjim economia la două zecimale, apoi să o scădem din subtotal. Nu rotunjim fiecare pas fără motiv. O altă politică poate produce un rezultat diferit pentru anumite intrări; tocmai de aceea regula trebuie scrisă înainte de implementare.

Pentru prețul 0.05, cantitatea unu și reducerea zece procente, economia exactă înainte de rotunjire este 0.005. Cu regula aleasă devine 0.01, iar totalul este 0.04. Acesta este un caz de test mai informativ decât un exemplu care se împarte exact. El demonstrează ce face programul la granița unei rotunjiri și permite verificarea independentă cu creionul pe hârtie.

Programul complet și contractul său

Creează calcul.py în directorul proiectului din lecția anterioară. Programul primește trei argumente text: prețul, cantitatea și procentul. Pentru preț acceptăm una până la cinci cifre înaintea punctului și opțional una sau două după el, cu valoare maximă 10000.00. Pentru procent acceptăm până la trei cifre întregi și opțional două zecimale, cu valoare între zero și o sută. Virgula nu este acceptată în această interfață.

Aceste limite țin exemplul lizibil și împiedică interpretarea unor intrări uriașe sau ambigue. Mesajul de eroare spune formatul așteptat. Nu înlocuim automat orice virgulă cu punct: o valoare precum 1,234 poate însemna lucruri diferite în contexte diferite. Un formular localizat ar trebui proiectat și testat separat.

import argparse
import re
from decimal import Decimal, ROUND_HALF_UP

parser = argparse.ArgumentParser(description="Calcul de atelier.")
parser.add_argument("pret")
parser.add_argument("cantitate")
parser.add_argument("procent")
args = parser.parse_args()

pret_text = args.pret.strip()
cantitate_text = args.cantitate.strip()
procent_text = args.procent.strip()

if not re.fullmatch(r"[0-9]{1,5}(\.[0-9]{1,2})?", pret_text):
    parser.error("Preț: cifre și opțional punct cu 1-2 zecimale.")
if not re.fullmatch(r"[0-9]{1,3}", cantitate_text):
    parser.error("Cantitate: 1-3 cifre, fără semne.")
if not re.fullmatch(r"[0-9]{1,3}(\.[0-9]{1,2})?", procent_text):
    parser.error("Procent: cifre și cel mult două zecimale.")

pret = Decimal(pret_text)
cantitate = int(cantitate_text)
procent = Decimal(procent_text)
if not pret.is_finite() or not Decimal("0") <= pret <= Decimal("10000"):
    parser.error("Prețul trebuie să fie între 0 și 10000.")
if not 1 <= cantitate <= 100:
    parser.error("Cantitatea trebuie să fie între 1 și 100.")
if not procent.is_finite() or not Decimal("0") <= procent <= Decimal("100"):
    parser.error("Procentul trebuie să fie între 0 și 100.")

subtotal = pret * cantitate
economie = (subtotal * procent / Decimal("100")).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)
total = subtotal - economie
print(f"Subtotal: {subtotal:.2f}")
print(f"Economie: {economie:.2f}")
print(f"Total: {total:.2f}")

re.fullmatch verifică întregul șir după un model. [0-9] permite cifrele indicate, iar {1,5} înseamnă între una și cinci repetări. Grupul opțional descrie punctul și zecimalele. Prefixul r păstrează convenabil barele inverse din model. Nu trebuie să inventezi expresii regulate complexe pentru orice câmp; aici modelul scurt exprimă exact gramatica anunțată.

Rulează în PowerShell .\.venv\Scripts\python.exe calcul.py 12.50 3 10. În bash/zsh folosește ./.venv/bin/python în locul executabilului Windows. Programul trebuie să afișeze cele trei sume din exemplul anterior. Versiunea completă separă clar trei etape: verificarea textului, verificarea domeniului numeric și calculul. Dacă apare o eroare, nu afișează un total de succes.

Laborator: cazul obișnuit nu este suficient

Pregătește un tabel cu intrarea, rezultatul așteptat și rezultatul observat. Pentru 12.50, 3 și 10, totalul este 33.75. Pentru aceleași preț și cantitate cu reducere zero, totalul este 37.50. Cu reducere o sută, totalul este 0.00. Pentru preț zero și cantitate trei, subtotalul și totalul sunt zero, iar comanda reușește. Astfel demonstrezi că zero este tratat potrivit sensului fiecărui câmp.

Testează apoi cantitatea zero, cantitatea 101 și procentul 100.01: toate trebuie respinse. Prețul 10000.00 este acceptat, iar 10000.01 este respins. Nu este de ajuns să testezi doar numere foarte mari; valorile imediat lângă limită găsesc greșeli precum < în loc de <=. Pentru fiecare respingere verifică atât mesajul, cât și absența liniei Total în ieșirea standard.

Adaugă intrările 12,50, NaN, Infinity și 1e2 ca preț. Contractul le respinge, chiar dacă unele au sens pentru alte parsere. Adaugă 3.0 și +3 pentru cantitate. Dacă un coleg dorește să le accepte, cere mai întâi schimbarea regulii și a testelor. O modificare a parserului este o schimbare a interfeței, nu o simplă corectură cosmetică.

Pentru rotunjire verifică 0.05, 1 și 10. Rezultatul trebuie să fie economia 0.01 și totalul 0.04. Apoi verifică 0.15, 1 și 10: economia 0.02 și totalul 0.13. Aceste cazuri expun regula ROUND_HALF_UP. Compară rezultatele cu calculul manual și explică de ce rotunjirea economiei nu este același lucru cu rotunjirea totalului calculat printr-o altă formulă.

Exercițiu de diagnostic cu rezolvare

Un coleg propune trei simplificări: înlocuiește Decimal cu float, validează prețul cu if not pret și convertește cantitatea prin int(float(text)). Analizează-le separat. Prima schimbă modelul numeric. A doua respinge incorect un preț zero. A treia poate transforma o cantitate fracționară în întreg și poate accepta forme pe care interfața inițială le refuza.

Rezolvarea nu este să adaugi rotunjiri până când un exemplu arată bine. Păstrează Decimal pornit din text, verifică explicit limitele și convertește cantitatea numai după validarea formei. Rulează din nou cazurile pentru zero, 3.5 și rotunjirea de jumătate de ban. O corectură este demonstrată când elimină cazul greșit și păstrează comportamentul celor valide.

Ca extensie, adaugă o taxă fixă fictivă de ambalare de 2.00, aplicată după reducere numai dacă totalul produselor este pozitiv. Scrie întâi așteptările: exemplul 33.75 devine 35.75, iar o reducere de o sută de procente lasă totalul zero și nu adaugă taxa. Aceasta este regula exercițiului, nu o practică comercială universală. Implementarea poate folosi o condiție total > Decimal("0") și o adunare explicită.

În registrul de lucru păstrează programul de bază și extensia separat, pentru a nu amesteca rezultatele. Explică în cuvinte unde se aplică reducerea și unde taxa. Dacă altcineva nu poate reproduce suma din regulile scrise, problema este încă incomplet definită, chiar dacă programul rulează fără excepții.

Lecția este încheiată când poți urmări traseul unei intrări de la text până la total, poți spune de ce fiecare respingere este justificată și poți reproduce calculele de control. Listele și dicționarele din lecția următoare vor permite aplicarea acestor reguli mai multor rânduri. Tipurile și limitele rămân aceleași responsabilități, chiar dacă volumul datelor crește.

De ce păstrăm separat calculul și mesajul

Să presupunem că vrei să afișezi totalul cu moneda lei. Expresia f"{total:.2f} lei" produce text pentru cititor. Dacă reasociezi numele total cu acel șir și încerci apoi să adaugi taxa de ambalare, ai pierdut valoarea numerică din acel nume. Păstrează total pentru Decimal și folosește un nume precum mesaj_total pentru reprezentarea destinată ecranului. Astfel, testele pot compara numerele, iar interfața poate schimba formularea fără să schimbe aritmetica.

Aceeași separare ajută când rezultatul ajunge într-un CSV. Dacă scrii „33.75 lei” într-o coloană pe care alt program o așteaptă numerică, ai schimbat contractul fișierului. O variantă clară este o coloană total cu reprezentarea 33.75 și o coloană moneda cu RON, atunci când proiectul chiar cere acea monedă. În laborator nu exportăm încă fișiere, dar pregătim această distincție pentru lecția despre CSV.

Un alt caz este comparația cu un rezultat așteptat. Pentru totalul demonstrativ verifică valoarea Decimal("33.75"), nu doar prezența textului 33 într-un mesaj. Un test textual prea permisiv poate accepta și 133.75 sau un mesaj de eroare care conține aceleași cifre. Când verifici comanda întreagă, compară liniile complete, codul de ieșire și canalul pe care este afișat mesajul. Când verifici calculul izolat, compară valorile numerice.

Pentru o probă de regresie, păstrează intrarea 12.50, 3, 10 și rezultatul exact înainte să adaugi taxa de ambalare. După extensie, rezultatul final se schimbă, dar subtotalul și economia trebuie să rămână identice. Această observație îți permite să localizezi o greșeală: dacă economia se schimbă, ai aplicat taxa prea devreme sau ai modificat formula reducerii. Un rezultat intermediar bine numit devine o probă despre ordinea operațiilor.

Exercițiul suplimentar este să afișezi patru linii: subtotal, economie, taxă și total. Pentru cazul de bază, valorile sunt 37.50, 3.75, 2.00 și 35.75. Pentru reducere integrală, sunt 37.50, 37.50, 0.00 și 0.00. Explică de ce taxa zero din al doilea caz este calculată conform regulii, nu o valoare lipsă. Ai astfel o verificare care leagă tipurile, condițiile și prezentarea rezultatului.

Documentație oficială

Ți-a plăcut lecția? Continuă cursul complet

Ai citit o lecție gratuită. Celelalte lecții, aplicațiile practice și materialele se deblochează odată cu cursul.

99 lei

Plată unică, acces pe viață la toate cele 7 lecții.

Vezi ce conține cursul →

Folosim cookie-uri esențiale pentru funcționarea site-ului și, cu acordul tău, cookie-uri de analiză și publicitate. Partenerii noștri, inclusiv Google, pot folosi cookie-uri pentru a afișa reclame relevante. Detalii în Politica de cookie-uri.