A la lliçó anterior vas aconseguir que les dades d'una tasca d'Estudi Alba visquessin en variables. El programa ja desa informació, però encara no hi fa res: no sap dir quants dies falten per al lliurament del logotip del Forn Solé, ni si aquesta tasca és urgent, ni quin percentatge de l'encàrrec porta completat el Luis.

Aquest salt —de desar a calcular— el fan els operadors. Un operador és un símbol que combina valors per produir-ne un de nou: + suma, > compara, and conjuga condicions. I la combinació de valors, variables i operadors s'anomena expressió. Tot programa, per complex que sigui, és en el fons una acumulació d'expressions que s'avaluen i de valors que s'assignen.

En aquesta lliçó aprendràs què és una expressió i en quin ordre s'avalua; els operadors aritmètics, amb especial atenció a aquells dos que se solen ignorar i resulten utilíssims (// i %); l'assignació composta (+= i companyia); els operadors de comparació, que sempre produeixen un booleà; els operadors lògics and, or i not amb la seva taula de veritat i la seva avaluació mandrosa; l'operador in de pertinença; la diferència entre == i is; i com funcionen + i * amb textos. Tancarem amb la precedència i amb l'aplicació de tot plegat a TascaFàcil.

Contingut

  1. Què és una expressió i com s'avalua
  2. Operadors aritmètics
  3. Divisió entera // i mòdul %: els dos infravalorats
  4. Assignació composta
  5. Operadors de comparació
  6. Operadors lògics i taula de veritat
  7. Avaluació mandrosa (curtcircuit)
  8. L'operador de pertinença in
  9. == davant d'is
  10. Operadors amb cadenes: + i *
  11. Precedència d'operadors
  12. TascaFàcil: calcular sobre les dades de la tasca
  13. Errors comuns i consells
  14. Exercicis
  15. Conclusió

  1. Què és una expressió i com s'avalua

Una expressió és qualsevol combinació de valors, variables i operadors que Python pot avaluar fins a reduir-la a un únic valor.

Aquestes són totes expressions:

7
7 + 3
dies_estimats * 8
hores_dedicades > 5
prioritat == "alta"

I aquesta no ho és: dies = 3. És una instrucció (una assignació), no una expressió. La distinció és fina però aclaridora:

Expressió Instrucció
Què fa Es redueix a un valor Realitza una acció
Exemple 7 + 3 → 10 total = 7 + 3
Es pot posar a la dreta d'un =? Sí No

Fixa't que una assignació conté una expressió: a total = 7 + 3, la part dreta és l'expressió i el = és l'acció de desar-ne el resultat.

Avaluar significa anar substituint cada peça pel seu valor fins que només en queda un. Amb aquest codi:

dies_estimats = 3
hores_per_dia = 8

hores_totals = dies_estimats * hores_per_dia
print(hores_totals)      # 24

Python fa el següent en arribar a la tercera línia:

dies_estimats * hores_per_dia
      3        *       8
                24

Primer substitueix cada nom pel valor al qual apunta, després aplica l'operador, i finalment assigna el resultat. Aquest ordre —valors primer, operació després, assignació al final— és el que has de tenir al cap en llegir qualsevol línia de codi.

Els valors sobre els quals actua un operador s'anomenen operands. A 3 * 8, l'operador és * i els operands són 3 i 8.

  1. Operadors aritmètics

Python ofereix set operadors aritmètics. Els tres primers no et sorprendran; els quatre següents mereixen atenció.

Operador Nom Exemple Resultat Tipus del resultat
+ Suma 7 + 3 10 int
- Resta 7 - 3 4 int
* Multiplicació 7 * 3 21 int
/ Divisió real 7 / 3 2.3333333333333335 float sempre
// Divisió entera 7 // 3 2 int (si tots dos són int)
% Mòdul (residu) 7 % 3 1 int
** Potència 7 ** 3 343 int

Vegem-los funcionant:

print(7 + 3)      # 10
print(7 - 3)      # 4
print(7 * 3)      # 21
print(7 / 3)      # 2.3333333333333335
print(7 // 3)     # 2
print(7 % 3)      # 1
print(7 ** 3)     # 343

Hi ha un parany clàssic a la quarta línia. / retorna sempre un float, encara que la divisió sigui exacta:

print(6 / 3)          # 2.0   <- no 2
print(type(6 / 3))    # <class 'float'>
print(6 // 3)         # 2
print(type(6 // 3))   # <class 'int'>

Si necessites un número enter —per comptar coses, per exemple— fes servir //, no /. Un comptador de tasques que val 2.0 en lloc de 2 produeix sortides lletges i comparacions confuses.

Un altre detall: si barreges un int i un float en qualsevol operació, el resultat és float. És la conversió implícita, i l'estudiarem amb més detall a Conversió de tipus i validació:

print(3 + 1.5)          # 4.5
print(type(3 + 1.5))    # <class 'float'>

Els signes negatius funcionen com esperes, i el - també es pot fer servir amb un sol operand (s'anomena menys unari):

diferencia = 3 - 5
print(diferencia)     # -2
print(-diferencia)    # 2

Un advertiment sobre / i //: dividir per zero és un error. 7 / 0 atura el programa amb ZeroDivisionError: division by zero. Quan el divisor vingui d'una dada variable (per exemple, el nombre de tasques d'una persona, que pot ser zero), caldrà comprovar-ho abans. Fer aquesta comprovació requereix condicionals, que arriben a Condicionals.

  1. Divisió entera // i mòdul %: els dos infravalorats

Aquests dos operadors se solen mirar per sobre i després resulten ser els que més es fan servir en problemes reals. Es mereixen el seu propi apartat.

Pensa en la divisió de tota la vida, la de l'escola: 17 entre 5 dóna 3 de quocient i 2 de residu. Doncs bé:

  • // et dóna el quocient enter: 17 // 5 → 3
  • % et dóna el residu: 17 % 5 → 2
minuts_totals = 195

hores = minuts_totals // 60     # 3
minuts = minuts_totals % 60     # 15

print(hores)      # 3
print(minuts)     # 15

195 minuts són 3 hores i 15 minuts. Aquesta parella d'operadors és la manera estàndard de descompondre una quantitat en unitats majors i menors: minuts en hores, dies en setmanes, cèntims en euros.

Aplicat a Estudi Alba: el Luis porta 27 hores dedicades a un encàrrec i treballa jornades de 8 hores. Quantes jornades completes hi ha invertit i quantes hores soltes van de la següent?

HORES_PER_JORNADA = 8
hores_dedicades = 27

jornades_completes = hores_dedicades // HORES_PER_JORNADA    # 3
hores_soltes = hores_dedicades % HORES_PER_JORNADA           # 3

print(jornades_completes)   # 3
print(hores_soltes)         # 3

L'altre gran ús de % és detectar múltiples. Un número és múltiple d'un altre quan el residu de dividir-los és zero:

numero_tasca = 12

print(numero_tasca % 2)     # 0  -> es parell
print(numero_tasca % 5)     # 2  -> no es multiple de 5

n % 2 == 0 significa «n és parell». És una construcció que veuràs mil vegades.

Necessitat Operador Exemple
Repartir en grups complets // 27 // 8 → 3 jornades senceres
Saber quant sobra del repartiment % 27 % 8 → 3 hores soltes
Comprovar si és múltiple / parell % 12 % 2 → 0, per tant és parell
Obtenir l'últim dígit % 1250 % 10 → 0
Valor exacte amb decimals / 27 / 8 → 3.375 jornades

Un avís sobre negatius, perquè no t'agafi per sorpresa: -7 // 2 dóna -4, no -3, perquè Python arrodoneix cap avall, no cap a zero. I -7 % 2 dóna 1, no -1. Amb quantitats positives —el 99 % dels casos— no notaràs la diferència.

  1. Assignació composta

Augmentar el valor d'una variable és tan freqüent que Python ofereix una forma abreujada. Aquestes dues línies fan exactament el mateix:

hores_dedicades = hores_dedicades + 2
hores_dedicades += 2

La segona es llegeix «suma 2 a hores_dedicades». Existeix una versió abreujada per a cada operador aritmètic:

Abreviatura Equival a Exemple (partint de x = 10) Resultat
x += 3 x = x + 3 13
x -= 3 x = x - 3 7
x *= 3 x = x * 3 30
x /= 4 x = x / 4 2.5 (float)
x //= 3 x = x // 3 3
x %= 3 x = x % 3 1
x **= 2 x = x ** 2 100

Un exemple amb el fil del curs: el Luis va anotant les hores que dedica al logotip al llarg de la setmana.

hores_dedicades = 0

hores_dedicades += 3.5      # dilluns
hores_dedicades += 2        # dimarts
hores_dedicades += 4        # dijous

print(hores_dedicades)      # 9.5

Fixa't en un detall imprescindible: la variable ha d'existir abans. hores_dedicades += 3.5 és hores_dedicades = hores_dedicades + 3.5, i per calcular la part dreta Python necessita saber quant val ara. Si no s'ha assignat mai, obtindràs NameError. Per això la primera línia la inicialitza a 0.

També funciona amb textos, perquè + concatena cadenes (ho veurem a l'apartat 10):

resum = "Tasca: "
resum += "logotip"
print(resum)                # Tasca: logotip

  1. Operadors de comparació

Els operadors de comparació responen a preguntes sobre dos valors. I ho fan d'una manera molt concreta: retornen sempre un valor booleà, True o False. Mai cap altra cosa.

Operador Significat Exemple Resultat
== Són iguals? 3 == 3 True
!= Són diferents? 3 != 5 True
> Més gran que? 3 > 5 False
< Més petit que? 3 < 5 True
>= Més gran o igual? 5 >= 5 True
<= Més petit o igual? 3 <= 2 False
dies_estimats = 3
dies_transcorreguts = 5

print(dies_transcorreguts > dies_estimats)    # True  -> hi ha retard
print(dies_estimats == dies_transcorreguts)   # False
print(dies_estimats != dies_transcorreguts)   # True

Aquest True que veus imprès no és un text decoratiu: és un valor de tipus bool, i com a tal es pot desar en una variable i fer-se servir després.

hi_ha_retard = dies_transcorreguts > dies_estimats
print(hi_ha_retard)         # True
print(type(hi_ha_retard))   # <class 'bool'>

Aquesta és una idea potent i convé subratllar-la: una comparació produeix una dada com qualsevol altra. No és una pregunta que es fa i s'oblida; és un valor que pots emmagatzemar, anomenar i reutilitzar. Quan arribin els condicionals al mòdul 3, aquest valor serà el que decideixi quin camí pren el programa.

Les comparacions també funcionen amb textos, i aquí hi ha dues coses a saber:

print("alta" == "alta")     # True
print("alta" == "ALTA")     # False  <- distingeixen majuscules
print("alta" < "mitjana")   # True   <- ordre alfabetic

La segona línia és exactament el problema que vam descobrir amb la prova d'escriptori de la lliçó 01-05: "ALTA" i "alta" són textos diferents per a Python. La solució arriba a Conversió de tipus i validació.

La tercera mostra que < i > comparen textos alfabèticament, caràcter a caràcter segons el seu codi intern. Compte: com que les majúscules van abans que les minúscules en aquest ordre, "Vidal" < "alba" és True. És una font de sorpreses en ordenar noms.

Python permet a més encadenar comparacions, cosa poc habitual en altres llenguatges i molt llegible:

dies = 5
print(1 <= dies <= 7)       # True  -> esta dins de la setmana

Això es llegeix tal qual: «dies està entre 1 i 7, tots dos inclosos».

  1. Operadors lògics i taula de veritat

Els operadors lògics combinen valors booleans per construir condicions compostes. Són tres:

Operador Significat Retorna True quan...
and I Tots dos operands són vertaders
or O Almenys un és vertader
not No Inverteix el valor de l'operand

En Python s'escriuen amb paraules en anglès, no amb símbols com && o || d'altres llenguatges.

Taula de veritat d'and:

A B A and B
True True True
True False False
False True False
False False False

Taula de veritat d'or:

A B A or B
True True True
True False True
False True True
False False False

Taula de veritat de not:

A not A
True False
False True

I ara amb dades d'Estudi Alba:

prioritat = "alta"
completada = False

es_urgent = prioritat == "alta" and not completada
print(es_urgent)            # True

Esmicolem aquesta expressió, perquè condensa gairebé tot el que hem vist fins ara:

prioritat == "alta"  and  not completada
      True           and  not False
      True           and     True
                  True
  1. prioritat == "alta" és una comparació → True.
  2. completada val False, així que not completada → True.
  3. True and True → True.

Es llegeix en català gairebé literalment: «és urgent si la prioritat és alta i no està completada». Quan una expressió lògica es llegeix bé en veu alta, sol estar ben escrita.

Ara a l'inrevés, amb la tasca ja acabada:

prioritat = "alta"
completada = True

es_urgent = prioritat == "alta" and not completada
print(es_urgent)            # False

not True és False, i True and False és False. La tasca és de prioritat alta però ja està feta: no és urgent. Correcte.

Un exemple amb or, per decidir si una tasca necessita revisió de la Marta:

prioritat = "mitjana"
hores_dedicades = 22
HORES_LIMIT = 20

necessita_revisio = prioritat == "alta" or hores_dedicades > HORES_LIMIT
print(necessita_revisio)    # True

No és de prioritat alta (False), però s'ha passat del límit d'hores (True). Amb or n'hi ha prou que se'n compleixi una: True.

Vés amb compte amb un error freqüentíssim en traduir del llenguatge natural. Això no funciona com sembla:

prioritat = "baixa"

# INCORRECTE
es_rellevant = prioritat == "alta" or "mitjana"
print(es_rellevant)         # mitjana  <- ni tan sols es un boolea

En català diem «la prioritat és alta o mitjana», però Python no ho llegeix així: avalua prioritat == "alta" (que dóna False) i després avalua "mitjana" pel seu compte, com a valor independent. Un text no buit compta com a vertader, així que l'or retorna "mitjana" i l'expressió resulta vertadera sempre, fins i tot amb una prioritat baixa. La forma correcta repeteix la comparació completa:

# CORRECTE
es_rellevant = prioritat == "alta" or prioritat == "mitjana"
print(es_rellevant)         # False

O, encara millor, fes servir l'operador in que veurem a l'apartat 8.

  1. Avaluació mandrosa (curtcircuit)

Python avalua les expressions lògiques d'esquerra a dreta i s'atura tan bon punt coneix el resultat. És el que s'anomena avaluació mandrosa o curtcircuit.

La lògica és senzilla:

  • A A and B: si A ja és False, el resultat serà False passi el que passi amb B. Python ni tan sols avalua B.
  • A A or B: si A ja és True, el resultat serà True. Python no avalua B.
flowchart TD
    A["Avaluar A and B"] --> B{"A es False?"}
    B -->|Si| C["Resultat False<br/>B no s'avalua"]
    B -->|No| D["Avaluar B"]
    D --> E["El resultat es el valor de B"]

Per què importa això? Per dos motius molt pràctics.

Primer, per eficiència. Si la part dreta és un càlcul costós, estalviar-se'l té valor.

Segon, i molt més important, per seguretat. El curtcircuit permet protegir una operació perillosa posant al davant la comprovació que la fa segura:

tasques_assignades = 0
hores_totals = 0

# Si tasques_assignades es 0, la divisio no s'executa mai
repartiment_ok = tasques_assignades > 0 and hores_totals / tasques_assignades < 10
print(repartiment_ok)      # False, sense ZeroDivisionError

Si Python avalués sempre tots dos costats, la divisió per zero trencaria el programa. Gràcies al curtcircuit, en ser tasques_assignades > 0 igual a False, la part dreta ni es mira. L'ordre dels operands en un and no és indiferent: primer la comprovació que protegeix, després l'operació protegida.

Un matís curiós que convé conèixer: en Python, and i or no retornen sempre True o False, sinó l'operand en què es van aturar.

print(0 or "sense assignar")       # sense assignar
print("Luis" or "sense assignar")  # Luis

Com que 0 compta com a fals, or continua i retorna el segon operand. Com que "Luis" compta com a vertader, s'atura i el retorna. És un idioma habitual per donar valors per defecte. Les regles exactes de quins valors compten com a vertaders les veuràs a Conversió de tipus i validació.

  1. L'operador de pertinença in

L'operador in respon a la pregunta «això és dins d'allò?» i retorna un booleà. Sobre textos, comprova si una cadena apareix dins d'una altra:

titol = "Logotip Forn Sole"

print("Sole" in titol)           # True
print("Vidal" in titol)          # False
print("sole" in titol)           # False  <- distingeix majuscules

La seva forma negada és not in:

print("Vidal" not in titol)      # True

in funciona sobre llistes, diccionaris i altres estructures que veuràs al mòdul 5. Però hi ha un ús que pots aprofitar des d'avui i que resol elegantment el problema de l'apartat 6: comprovar si un valor és entre diversos possibles.

prioritat = "mitjana"

# Versio llarga
es_valida = prioritat == "alta" or prioritat == "mitjana" or prioritat == "baixa"

# Versio curta i clara
es_valida = prioritat in ("alta", "mitjana", "baixa")

print(es_valida)      # True

Els parèntesis amb valors separats per comes formen una tupla, una col·lecció fixa de valors que s'estudia a Tuples i estructures imbricades. Aquí la fem servir només com a llista d'opcions vàlides: és llegible, s'amplia afegint-hi un valor i evita repetir tres vegades el nom de la variable. Serà la nostra eina principal per validar la prioritat a la lliçó 02-04.

Un avís sobre in en textos: comprova subcadenes, no paraules completes. "alta" in "prioritat molt alta" és True, però també ho és "alta" in "opcio altament recomanada". Per a valors concrets, prefereix in amb una tupla d'opcions abans que in sobre un text llarg.

  1. == davant d'is

Aquests dos operadors semblen sinònims i no ho són. La distinció s'entén bé amb el model d'etiquetes i valors de la lliçó anterior:

  • == pregunta: valen el mateix?
  • is pregunta: són exactament el mateix objecte en memòria?
responsable_a = "Luis"
responsable_b = "Luis"

print(responsable_a == responsable_b)   # True  -> mateix contingut
print(responsable_a is responsable_b)   # True o False, segons optimitzacions internes

Aquesta segona línia és justament el problema: el resultat d'is amb textos i números depèn de detalls interns de Python que no controles i que poden canviar entre versions. Amb textos curts Python reutilitza el mateix objecte i dóna True; amb textos construïts en temps d'execució pot donar False encara que el contingut sigui idèntic.

La regla pràctica és simple i no admet excepcions al nivell d'aquest curs:

Vols saber... Fes servir No facis servir mai
Si dues dades tenen el mateix valor == is
Si una variable és None is None == None

És a dir: fes servir sempre == per comparar valors, i reserva is per a un únic cas, comprovar None:

data_lliurament = None

print(data_lliurament is None)        # True
print(data_lliurament is not None)    # False

Per què aquí sí is? Perquè None és un valor únic en tota l'execució de Python: només n'existeix un. Preguntar si alguna cosa «és aquest objecte» és exactament el que vols, i és la forma que veuràs en tot el codi professional.

  1. Operadors amb cadenes: + i *

Dos operadors aritmètics tenen un segon significat quan treballen amb textos.

+ concatena, és a dir, enganxa dues cadenes en una:

nom = "Forn"
cognom = "Sole"

client = nom + " " + cognom
print(client)       # Forn Sole

Fixa't en el " " del mig: la concatenació no afegeix espais. Sense ell obtindries FornSole. És l'oblit més comú en concatenar.

* repeteix una cadena un nombre enter de vegades:

separador = "-" * 40
print(separador)    # ----------------------------------------

print("=" * 10)     # ==========

És la manera habitual de dibuixar línies separadores sense escriure quaranta guions a mà. Ho farem servir a la fitxa de TascaFàcil.

I ara el límit important. No es pot sumar un text i un número:

dies = 3
print("Dies: " + dies)
TypeError: can only concatenate str (not "int") to str

El missatge diu literalment: «només es pot concatenar str amb str, no amb int». Python no endevina el que vols. I fa bé: "3" + 4 podria ser 7 o "34", i l'ambigüitat en un llenguatge de programació és pitjor que un error.

La solució passa per convertir el número a text amb str(), i això es veu a Conversió de tipus i validació. A la pràctica, per barrejar text i dades faràs servir les f-strings d'Entrada i sortida de dades, que són molt més còmodes. Per això en aquesta lliçó continuem imprimint cada valor en el seu propi print.

Operador Amb números Amb textos
+ Suma: 3 + 4 → 7 Concatena: "a" + "b" → "ab"
* Multiplica: 3 * 4 → 12 Repeteix: "ab" * 3 → "ababab"
- Resta: 7 - 3 → 4 Error: TypeError
/ Divideix Error: TypeError

  1. Precedència d'operadors

Quan una expressió combina diversos operadors, Python aplica un ordre fix anomenat precedència, igual que en matemàtiques la multiplicació va abans que la suma.

print(2 + 3 * 4)      # 14, no 20

De major a menor prioritat:

Nivell Operadors Exemple
1 (més alta) () parèntesis (2 + 3) * 4 → 20
2 ** potència 2 ** 3 * 4 → 32
3 -x menys unari -2 ** 2 → -4
4 *, /, //, % 2 + 3 * 4 → 14
5 +, -
6 ==, !=, <, >, <=, >=, in, is 2 + 3 > 4 → True
7 not
8 and
9 (més baixa) or

Dues conseqüències que convé retenir:

Les comparacions s'avaluen després de l'aritmètica. Per això 2 + 3 > 4 funciona: primer suma (5), després compara (5 > 4 → True). No calen parèntesis.

and s'avalua abans que or. Això sí que sorprèn:

print(True or False and False)     # True

S'agrupa com True or (False and False) → True or False → True. Si haguessis volgut (True or False) and False, el resultat seria False. Aquí els parèntesis no són opcionals: són la diferència entre dos programes diferents.

I el consell pràctic, que val més que la taula sencera: fes servir parèntesis sempre que l'expressió no sigui evident. No costen res, no alenteixen el programa i eviten que qui llegeixi el codi —o tu mateix d'aquí a un mes— hagi de consultar una taula de precedències.

# Correcte pero exigeix coneixer la taula
es_critica = prioritat == "alta" and not completada or hores_dedicades > 40

# Correcte i evident
es_critica = (prioritat == "alta" and not completada) or (hores_dedicades > 40)

Les dues línies fan el mateix. La segona s'entén sense pensar.

  1. TascaFàcil: calcular sobre les dades de la tasca

Apliquem tot l'après a tascafacil.py. Partim de les variables de la versió 0.2 i hi afegim càlculs: els dies que falten per al lliurament, si la tasca és urgent i el percentatge d'avanç de l'encàrrec del Forn Solé.

# tascafacil.py - Estudi Alba
# Versio 0.3: calculs sobre les dades de la tasca

NOM_APP = "TascaFacil"
VERSIO = "0.3"
HORES_PER_JORNADA = 8

# --- Dades de la tasca ---
titol = "Logotip Forn Sole"
responsable = "Luis"
prioritat = "alta"
completada = False

dia_actual = 12               # dia del mes en que som
dia_lliurament = 19           # dia del mes acordat amb el client
hores_estimades = 24          # pressupost d'hores de l'encarrec
hores_dedicades = 9           # hores que el Luis porta invertides

print("=" * 40)
print("  TASCAFACIL v0.3 - Estudi Alba")
print("=" * 40)
print(titol)
print(responsable)
print("-" * 40)

# --- 1. Dies que falten per al lliurament ---
dies_restants = dia_lliurament - dia_actual
print("Dies restants:")
print(dies_restants)                        # 7

# --- 2. Jornades i hores soltes dedicades ---
jornades = hores_dedicades // HORES_PER_JORNADA
hores_soltes = hores_dedicades % HORES_PER_JORNADA
print("Jornades completes dedicades:")
print(jornades)                             # 1
print("Hores soltes:")
print(hores_soltes)                         # 1

# --- 3. Percentatge d'avanc ---
percentatge_avanc = hores_dedicades / hores_estimades * 100
print("Percentatge d'avanc:")
print(percentatge_avanc)                    # 37.5

# --- 4. Hores que queden i ritme necessari ---
hores_restants = hores_estimades - hores_dedicades
print("Hores restants:")
print(hores_restants)                       # 15

# --- 5. Es urgent? ---
es_urgent = prioritat == "alta" and not completada
print("Es urgent:")
print(es_urgent)                            # True

# --- 6. Prioritat valida? ---
prioritat_valida = prioritat in ("alta", "mitjana", "baixa")
print("Prioritat valida:")
print(prioritat_valida)                     # True

# --- 7. Va amb retard? ---
# Es considera endarrerida si ha consumit mes del 60 % del pressupost
# d'hores i encara queden menys de 5 dies
va_just = (percentatge_avanc > 60) and (dies_restants < 5)
print("Va just de termini:")
print(va_just)                              # False

Anem a comentar els càlculs que tenen substància.

Dies restants (dia_lliurament - dia_actual). Una resta senzilla que només funciona dins del mateix mes; per a dates reals existeix el mòdul datetime de Python, que queda fora d'aquest curs introductori. El rellevant aquí és que la dada ja no està escrita: es calcula. Si canvies dia_actual a 17, dies_restants passa a 2 sense tocar res més.

Percentatge d'avanç (hores_dedicades / hores_estimades * 100). Nota que aquí fem servir / i no //: volem el valor exacte amb decimals. Amb 9 hores de 24, el resultat és 37.5. I observa la precedència: / i * tenen el mateix nivell, així que s'avaluen d'esquerra a dreta: primer 9 / 24 (= 0.375) i després * 100 (= 37.5). És el que volíem.

Jornades i hores soltes (// i %). 9 hores amb jornades de 8 són 1 jornada completa i 1 hora solta. És el patró de l'apartat 3 aplicat a una dada real.

És urgent (prioritat == "alta" and not completada). L'expressió que resumeix la regla de negoci de la Marta. És alta i no està feta: urgent. Prova de posar completada = True i executar de nou: passa a False.

Va just de termini. Aquí els parèntesis no eren necessaris per precedència (les comparacions van abans que and), però s'han posat perquè la línia es llegeixi d'un cop d'ull. Aquest és exactament el criteri que has d'aplicar.

Prova d'escriptori de l'expressió d'urgència

Com al mòdul 1, verifiquem la lògica amb una taula, sense executar res:

Cas prioritat completada prioritat == "alta" not completada es_urgent
1 "alta" False True True True
2 "alta" True True False False
3 "mitjana" False False True False
4 "mitjana" True False False False
5 "ALTA" False False True False ← problema

Els quatre primers casos són correctes. El cinquè torna a posar el dit a la nafra: si la Marta escriu la prioritat en majúscules, la comparació falla i una tasca urgent passa desapercebuda. No és una fallada de l'expressió lògica, sinó de les dades que li arriben. Aquesta és la feina de la validació, i la resoldrem a 02-04.

Errors Comuns i Consells

Fer servir = en lloc de == en comparar. prioritat = "alta" assigna; prioritat == "alta" compara. En Python modern, posar = on va == dins d'una condició dóna SyntaxError, cosa que és una sort: l'error salta de seguida.

Esperar un enter de /. 10 / 2 és 5.0, un float. Si comptes coses, fes servir //.

Dividir entre zero. ZeroDivisionError. Quan el divisor sigui una dada variable, protegeix-lo amb un and aprofitant el curtcircuit, o amb un condicional quan arribis al mòdul 3.

Escriure and, or i not com a símbols. En Python no existeixen &&, || ni !. Són paraules.

El parany de x == "alta" or "mitjana". Sembla català i no ho és. Repeteix la comparació sencera o, millor, fes servir x in ("alta", "mitjana").

Fer servir is per comparar valors. Funciona per casualitat amb textos curts i falla just quan el programa ja és en ús. == per a valors; is només amb None.

Concatenar text i número amb +. "Dies: " + 3 dóna TypeError. Espera't a les f-strings de la propera lliçó: és la solució còmoda.

Oblidar l'espai en concatenar. "Forn" + "Sole" produeix FornSole. L'espai s'ha de posar explícitament.

Fiar-se de la precedència de memòria. Ningú no recorda si not va abans que and. Posa parèntesis i deixa de pensar-hi.

Confiar en la comparació exacta de float. 0.1 + 0.2 == 0.3 és False, perquè els decimals s'emmagatzemen de manera aproximada. Amb diners o mesures, compara amb un marge de tolerància en lloc d'exigir igualtat exacta.

Consell: anomena les expressions lògiques. En comptes de repetir prioritat == "alta" and not completada en diversos llocs, desa-la a es_urgent i fes servir el nom. El codi es llegeix com una frase i, si la regla canvia, es toca en un sol lloc.

Consell: fes servir el REPL com a calculadora. Quan dubtis de què dóna -7 // 2 o "alta" < "mitjana", no raonis: obre l'intèrpret i prova-ho. Trigues cinc segons i surts de dubtes per sempre.

Exercicis

Exercici 1: Avaluar expressions a mà

Escriu el resultat i el tipus de cada expressió sense executar res. Després comprova-ho al REPL.

a)  17 // 5
b)  17 % 5
c)  17 / 5
d)  2 ** 5
e)  10 - 4 * 2
f)  (10 - 4) * 2
g)  7 // 2 == 3
h)  "alta" == "Alta"
i)  not (3 > 5)
j)  True and False or True
k)  "prio" in "prioritat"
l)  "-" * 5
m)  1 <= 4 <= 3

Exercici 2: Repartiment d'hores a Estudi Alba

La Marta reparteix la feina d'un encàrrec gran. Escriu un programa que, partint d'aquestes variables, calculi i mostri el que es demana:

hores_encarrec = 100
persones = 3
HORES_PER_JORNADA = 8
hores_ja_fetes = 37

Calcula:

  1. Quantes hores completes toquen a cada persona (sense decimals).
  2. Quantes hores sobren del repartiment i no es poden repartir per igual.
  3. El repartiment exacte amb decimals.
  4. El percentatge de l'encàrrec ja realitzat.
  5. Quantes jornades completes de 8 hores queden per fer.
  6. Un booleà mes_de_la_meitat que indiqui si s'ha superat el 50 % de l'encàrrec.

Exercici 3: Regles de negoci de TascaFàcil

La Marta ha concretat tres regles noves. Escriu-les com a expressions booleanes desades en variables amb nom, partint d'aquestes variables de partida:

prioritat = "mitjana"
completada = False
responsable = "Nuria"
dies_restants = 2
hores_dedicades = 18
hores_estimades = 20

Les regles:

  • necessita_atencio_avui: la tasca no està completada i, o bé és de prioritat alta, o bé queden menys de 3 dies per al lliurament.
  • es_passa_de_pressupost: s'ha consumit més del 85 % de les hores estimades i la tasca continua sense completar.
  • es_de_disseny: el responsable és el Luis o la Nuria (la Marta coordina, no dissenya).

Després, indica quin valor té cadascuna amb les dades de dalt i afegeix una prova d'escriptori de necessita_atencio_avui per a tres escenaris diferents.

Solucions

Solució 1.

Expressió Resultat Tipus Explicació
a 17 // 5 3 int Quocient enter
b 17 % 5 2 int Residu
c 17 / 5 3.4 float / sempre retorna decimal
d 2 ** 5 32 int 2 elevat a 5
e 10 - 4 * 2 2 int * abans que -: 10 - 8
f (10 - 4) * 2 12 int Els parèntesis canvien l'ordre
g 7 // 2 == 3 True bool // abans que ==: 3 == 3
h "alta" == "Alta" False bool Distingeix majúscules
i not (3 > 5) True bool 3 > 5 és False; not False és True
j True and False or True True bool and primer: (True and False) or True → False or True
k "prio" in "prioritat" True bool És una subcadena
l "-" * 5 "-----" str Repetició de cadena
m 1 <= 4 <= 3 False bool 1 <= 4 sí, però 4 <= 3 no

Solució 2.

hores_encarrec = 100
persones = 3
HORES_PER_JORNADA = 8
hores_ja_fetes = 37

# 1. Hores completes per persona
hores_per_persona = hores_encarrec // persones
print(hores_per_persona)            # 33

# 2. Hores que sobren del repartiment
hores_sobrants = hores_encarrec % persones
print(hores_sobrants)               # 1

# 3. Repartiment exacte
repartiment_exacte = hores_encarrec / persones
print(repartiment_exacte)           # 33.333333333333336

# 4. Percentatge realitzat
percentatge_fet = hores_ja_fetes / hores_encarrec * 100
print(percentatge_fet)              # 37.0

# 5. Jornades completes que queden
hores_pendents = hores_encarrec - hores_ja_fetes
jornades_pendents = hores_pendents // HORES_PER_JORNADA
print(hores_pendents)               # 63
print(jornades_pendents)            # 7

# 6. S'ha passat de la meitat?
mes_de_la_meitat = percentatge_fet > 50
print(mes_de_la_meitat)             # False

Comentaris sobre les decisions preses:

  • A 1 i 2 es fan servir // i % perquè el repartiment ha de ser en hores enteres: 33 hores per a cadascun i 1 hora que sobra i caldrà assignar a algú.
  • A 3 es fa servir / perquè allà sí que interessa el valor exacte. Els decimals interminables es podran presentar de manera llegible amb les f-strings de la propera lliçó.
  • A 5 es fa servir //: 63 hores pendents donen 7 jornades completes (i en sobrarien 7 hores, que s'obtindrien amb 63 % 8).

Solució 3.

prioritat = "mitjana"
completada = False
responsable = "Nuria"
dies_restants = 2
hores_dedicades = 18
hores_estimades = 20

necessita_atencio_avui = (not completada) and (prioritat == "alta" or dies_restants < 3)
print(necessita_atencio_avui)       # True

percentatge_consumit = hores_dedicades / hores_estimades * 100
es_passa_de_pressupost = percentatge_consumit > 85 and not completada
print(es_passa_de_pressupost)       # True

es_de_disseny = responsable in ("Luis", "Nuria")
print(es_de_disseny)                # True

Les tres són True amb les dades de partida:

  • necessita_atencio_avui: no està completada (True) i, encara que la prioritat no és alta (False), queden 2 dies, que és menys de 3 (True). L'or dóna True i l'and també. Els parèntesis al voltant de l'or són imprescindibles: sense ells, and s'avaluaria primer i la regla significaria una altra cosa.
  • es_passa_de_pressupost: 18 de 20 hores és el 90 %, que supera el 85 %, i no està completada.
  • es_de_disseny: la Nuria és a la tupla de dissenyadors.

Prova d'escriptori de necessita_atencio_avui:

Escenari completada prioritat dies_restants not completada prioritat == "alta" dies_restants < 3 or Resultat
Tasca de la Nuria, termini curt False "mitjana" 2 True False True True True
Tasca del Luis, alta, amb marge False "alta" 10 True True False True True
Tasca ja lliurada, alta True "alta" 1 False True True True False

El tercer escenari és el que valida el disseny de la regla: per molt alta que sigui la prioritat i per molt a prop que estigui el termini, una tasca completada no necessita atenció. El not completada a la part esquerra de l'and talla qualsevol altra consideració, i a més ho fa per curtcircuit: en ser False, Python ni tan sols avalua el parèntesi de l'or.

Conclusió

Les teves variables han deixat d'estar quietes. Ara saps que una expressió és qualsevol combinació de valors, variables i operadors que Python redueix a un únic valor, i que s'avalua substituint primer cada nom pel seu valor i aplicant després els operadors en ordre de precedència.

Manegues els set operadors aritmètics, amb la distinció crítica entre / (sempre float) i // (enter), i saps que % no és una curiositat matemàtica sinó l'eina estàndard per descompondre quantitats i detectar múltiples. Escrius increments amb assignació composta (+=). Saps que les comparacions produeixen booleans que pots desar i anomenar, que els operadors lògics and, or i not es comporten segons taules de veritat predictibles, i que la seva avaluació mandrosa no només estalvia feina sinó que permet protegir operacions perilloses col·locant la comprovació a l'esquerra. Fas servir in per preguntar per pertinença, reserves is exclusivament per a None, concatenes i repeteixes cadenes amb + i *, i poses parèntesis sempre que la precedència no sigui òbvia.

TascaFàcil és a la seva versió 0.3 i ja calcula: dies restants fins al lliurament, jornades invertides, percentatge d'avanç de l'encàrrec del Forn Solé i una expressió d'urgència (prioritat == "alta" and not completada) que tradueix a codi una regla de negoci real de la Marta.

I tanmateix el programa continua tenint dues mancances evidents. La primera és de presentació: cada dada necessita el seu propi print i la fitxa resultant és il·legible; no hem pogut barrejar text i valors en una sola línia perquè "Dies: " + 3 dóna TypeError. La segona és més de fons: totes les dades continuen escrites dins del codi. Per registrar una altra tasca cal obrir l'editor.

Totes dues es resolen a la lliçó següent, Entrada i sortida de dades, on aprendràs a donar format professional a la sortida amb f-strings i a demanar les dades a l'usuari per teclat amb input(). A partir d'aquí, TascaFàcil deixarà de ser un programa que s'edita per convertir-se en un programa que es fa servir.

© Copyright 2026. Tots els drets reservats