Python bàsic
- Programes
- Execució
- Hola, món
- Estructura i sintaxi
- Tipus de dades
- Variables
- Aritmètica i condicions
- Conversions
- Cadenes
- Control de flux
- Funcions
- Organització del codi
- Col·leccions
- Classes i objectes
- Herència
- Classes abstractes
- Gestió d’errors
- Context managers
- Anotacions de tipus
- Python idiomàtic
- Referències
Programes
Els programes consten de mòduls. Els mòduls, al seu torn, poden contenir instruccions, definicions de funcions i/o definicions de classe. Cada mòdul està associat a un fitxer font (extensió .py) i possiblement a un fitxer de bytecode (extensió .pyc).
Un compilador/intèrpret anomenat màquina virtual de Python (PVM) tradueix els fitxers font de Python a bytecode abans de l’execució. La PVM pot desar el bytecode corresponent en fitxers per a execucions posteriors.
Execució
Un programa en Python es pot executar com a script des d’una línia d’ordres:
python helloworld.py
Errors de sintaxi es detecten abans d’executar el programa. Errors de tipus (TypeError) es detecten en temps d’execució.
Hola, món
La versió més senzilla d’aquest programa consisteix en una sola instrucció:
print("Hello, world!")
L’ordre print converteix automàticament les dades en text, les mostra i mou el cursor a la línia següent:
print("Hello, world!")
print(34)
print("Hello, world!", end="") # evita el salt de línia
Una altra versió integra aquesta instrucció en una funció principal que es crida al final del mòdul:
def main():
print("Hello, world!")
main()
També tenim entrada des del teclat:
name = input("Enter your name: ") # cadena
age = int(input("Enter your age: ")) # sencer
Estructura i sintaxi
-
Els literals inclouen números, cadenes, tuples, llistes i diccionaris.
-
Els identificadors inclouen els noms de variables, classes, funcions i mètodes.
-
Les paraules reservades inclouen les de les principals sentències de control (
if,while,for,import, etc.), operadors (in,is, etc.), definicions (def,class, etc.) i valors especials (True,False,None, etc.). -
Els elements lèxics d’una sola línia estan separats per zero o més espais.
-
La sagnia és significativa i s’utilitza per marcar estructures sintàctiques, com ara blocs d’instruccions i codi dins de definicions de funcions, classes i mètodes.
-
Una frase es pot trencar i continuar a la línia següent després d’una coma o mitjançant el símbol
\. -
Les capçaleres de les instruccions de control i les definicions de funcions, classes i mètodes acaben amb dos punts (
:). -
Un comentari de final de línia comença amb el símbol
#:# This is a comment # spanning multiple lines.Els docstring, que comencen amb
"""i acaben amb""", documenten funcions, classes o mòduls:""" This is a docstring spanning multiple lines. """
Tipus de dades
Tots els valors de dades, incloses les funcions, són objectes. I totes les variables són referències a aquests objectes.
intrepresenta nombres sencers:42,-7,0floatrepresenta nombres de coma flotant amb precisió doble:3.14,-0.5boolrepresenta valors booleans:TrueoFalse. És una subclasse deint, onTrueequival a1iFalsea0.strrepresenta cadenes de text:"hello",'world'Noneés un valor especial que indica l’absència de valor. És l’únic valor del tipusNoneType.
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type(True)) # <class 'bool'>
print(type("hi")) # <class 'str'>
print(type(None)) # <class 'NoneType'>
Variables
Una variable s’introdueix i s’estableix a un valor inicial mitjançant una instrucció d’assignació:
<variable> = <expressió>
x = 1
x = x + 3.14
- Una variable s’introdueix i s’estableix a un valor inicial mitjançant una instrucció d’assignació.
- Qualsevol variable pot anomenar qualsevol objecte i es pot reiniciar a qualsevol objecte.
- La variable selecciona el tipus de l’objecte al qual està vinculada.
- La comprovació de tipus i la comprovació de referències a variables no inicialitzades es realitzen en temps d’execució.
Les variables en si mateixes no tenen tipus. L’objecte al qual fa referència una variable té un tipus.
Aritmètica i condicions
Els operadors aritmètics inclouen +, -, *, /, %, // i ** (exponenciació).
L’operació / retorna sempre un float, i l’operació // un sencer, sempre que els operands siguin sencers.
max, min, abs i round són funcions estàndard (round retorna un nombre sencer).
El mòdul math inclou funcions per a trigonometria, logaritmes, arrels quadrades, etc.
round(3.14) # 3
math.sqrt(2) # 1.4142...
Els operadors de comparació són ==, !=, <, >, <= i >=. Tots retornen True o False.
print("AAB" > "AAA") # True
El tipus booleà bool inclou els valors constants True i False (amb majúscules).
Altres valors, com ara 0, '', [] i None, també signifiquen False. Pràcticament qualsevol altre valor significa True.
Els operadors lògics són not, and i or. L’avaluació en curtcircuit s’atura quan hi ha prou informació disponible per retornar un valor. not s’avalua abans de and, que s’avalua abans de or.
Conversions
Els tipus numèrics es poden convertir a altres tipus numèrics amb les funcions de conversió:
int(3.14) # 3
float(3) # 3.0
Les funcions ord i chr s’utilitzen per convertir entre sencers i caràcters:
ord('A') # 65
chr(65) # 'A'
La funció str converteix qualsevol objecte Python a la seva representació de cadena:
str(45) # '45'
str(3.14) # '3.14'
Cadenes
- Una cadena és una seqüència de 0 o més caràcters.
- Les cadenes són instàncies de la classe
stri són objectes immutables. - La funció
lenretorna el nombre de caràcters d’una cadena. - L’operador de subíndex
[]accedeix a un caràcter en una posició determinada.
greeting = "Hello, world!"
print(len(greeting)) # 13
print(greeting[0]) # 'H'
print(greeting[-1]) # '!'
- Les cadenes es poden comparar amb els operadors de comparació estàndard
==,<, etc. - Els literals de cadena es formen amb cometes simples o dobles com a delimitadors.
- Les seqüències d’escapada es formen amb
\seguit d’una lletra adequada com aranot.
L’operador de concatenació + uneix dues cadenes per formar una tercera cadena nova:
str(35) + " pages long."
Mètodes de cadena
La classe str inclou molts mètodes útils:
| Mètode | Descripció | Exemple |
|---|---|---|
upper() | Converteix a majúscules | "hello".upper() → "HELLO" |
lower() | Converteix a minúscules | "HELLO".lower() → "hello" |
strip() | Elimina espais dels extrems | " hi ".strip() → "hi" |
split(sep) | Divideix en una llista | "a,b,c".split(",") → ["a","b","c"] |
join(iterable) | Uneix elements amb la cadena com a separador | ",".join(["a","b"]) → "a,b" |
replace(old, new) | Substitueix totes les ocurrències | "aab".replace("a","x") → "xxb" |
startswith(s) | Comprova si comença per s | "hello".startswith("he") → True |
find(s) | Retorna la posició de la primera ocurrència | "hello".find("ll") → 2 |
F-strings
Les f-strings permeten incrustar expressions directament dins de literals de cadena:
name = "Maria"
age = 25
message = f"Hello, my name is {name} and I am {age} years old."
A dins de les claus pot haver-hi expressions. Si són números, es poden formatar després dels dos punts:
pi = 3.14159
print(f"Pi is approximately {pi:.2f}") # Pi is approximately 3.14
Control de flux
if
if <boolean expression>:
<statement>
...
elif <boolean expression>:
<statement>
...
else:
<statement>
...
Les sentències del conseqüent i de cada alternativa estan marcades amb sagnat.
match
La instrucció match (Python 3.10+) compara un valor contra una sèrie de patrons i executa la branca corresponent:
match command:
case "quit":
print("Quitting.")
case "help":
print("Showing help.")
case _:
print(f"Unknown command: {command}")
Els patrons poden incloure valors literals, tuples, llistes, classes i guards (if):
match point:
case (0, 0):
print("Origin")
case (x, 0):
print(f"On x-axis at {x}")
case (x, y):
print(f"At ({x}, {y})")
while
while <boolean expression>:
<statement>
...
L’instrucció break surt d’un bucle:
while True:
break
L’instrucció pass no fa res:
while True:
pass
for
Només hi ha un tipus de bucle for, que visita cada element d’un objecte iterable:
for <variable> in <iterable>:
<statement>
...
words = ["apple", "banana", "cherry"]
for word in words:
print(word)
Els bucles simples controlats per recompte utilitzen range:
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 5): # 2, 3, 4
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8
print(i)
L’instrucció return surt d’una funció o mètode. Si no s’especifica cap expressió, es retorna None.
Funcions
A diferència dels mètodes, que són funcions associades a un objecte o una classe, Python disposa de funcions independents que no pertanyen a cap objecte i que es poden cridar directament:
def add(a, b):
return a + b
result = add(3, 4)
print(result) # 7
Python inclou moltes funcions built-in que es poden utilitzar sense importar cap mòdul:
| Funció | Descripció | Exemple |
|---|---|---|
print | Escriu dades a la sortida estàndard | print("Hello") |
len | Retorna la longitud d’una col·lecció o cadena | len("abc") retorna 3 |
type | Retorna el tipus d’un objecte | type(3) retorna <class 'int'> |
int | Converteix un valor a enter | int("10") retorna 10 |
str | Converteix un valor a cadena | str(5) retorna "5" |
range | Genera una seqüència d’enters | list(range(3)) retorna [0,1,2] |
input | Llegeix entrada des del teclat | input("Type something: ") |
Àmbit de les variables
Python resol els noms seguint l’ordre LEGB:
- Local: dins de la funció actual
- Enclosing: funció externa si hi ha funcions niades
- Global: del mòdul actual
- Built-in: funcions i noms predefinits de Python, com
len,print
global fa que una variable dins d’una funció faci referència a la definida al nivell global del mòdul. Sense global, una assignació dins d’una funció crea una variable local.
nonlocal fa que una variable dins d’una funció interna faci referència a la definida a la funció externa.
Arguments per defecte i nominals
Els paràmetres d’una funció poden tenir valors per defecte:
def greet(name="World"):
print(f"Hello, {name}!")
greet() # Hello, World!
greet("Julian") # Hello, Julian!
Els arguments també es poden passar per nom, independentment de l’ordre:
def show_info(name, age):
print(f"Name: {name}, Age: {age}")
show_info(age=25, name="Anna")
Arguments variables
*args captura arguments posicionals i **kwargs captura arguments amb nom (keyword arguments):
def show(*args, **kwargs):
print(args, kwargs)
show(1, 2, 3, name="Anna", age=25)
# (1, 2, 3) {'name': 'Anna', 'age': 25}
Funcions com a objectes
Les funcions a Python són objectes de primera classe: es poden assignar a variables, passar com a arguments i retornar des de funcions.
def square(x):
return x * x
f = square
print(f(5)) # 25
def apply(f, value):
return f(value)
print(apply(square, 7)) # 49
Funcions lambda
Les funcions lambda són funcions anònimes definides en una sola línia:
add = lambda a, b: a + b
print(add(3, 4)) # 7
numbers = [1, 4, 2, 5]
sorted_desc = sorted(numbers, key=lambda x: -x)
print(sorted_desc) # [5, 4, 2, 1]
Closures
Es poden definir funcions dins d’altres funcions. Quan una funció interna recorda l’estat de les variables externes, es diu que és un closure:
def multiplier(n):
def multiply(x):
return x * n
return multiply
times_3 = multiplier(3)
print(times_3(10)) # 30
Decoradors
Un decorador és una funció que envolta una altra funció (o classe) per afegir-hi comportament. La sintaxi @nom és equivalent a f = nom(f) aplicat just després de la definició:
def shout(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
@shout
def greet(name):
return f"hello, {name}"
print(greet("world")) # HELLO, WORLD
Python i les seves biblioteques estàndard proporcionen molts decoradors predefinits que s’utilitzen al llarg d’aquest document: @classmethod, @staticmethod, @property, @dataclass, @abstractmethod i @total_ordering.
Organització del codi
Els mòduls de Python s’utilitzen per defecte en la forma de singletons, com els mòduls de JavaScript. Comparativament a llenguatges com Java, les classes només s’utilitzen quan cal estat individual.
Un exemple de singleton:
value = 0
def increment():
global value
value += 1
return value
Mòduls
Un mòdul és un fitxer .py amb definicions (funcions, classes, constants…). S’importa amb:
import <module name>
Els recursos del mòdul es referencien com <module name>.<resource name>:
import math
print(math.sqrt(2), math.pi)
Alternativament, es pot importar un recurs individual:
from math import sqrt, pi
print(sqrt(2), pi)
Es pot assignar un àlies per escurçar o evitar conflictes:
from datetime import datetime as dt
Paquets
Un paquet és un directori que conté un arxiu especial __init__.py i altres mòduls:
mypackage/
__init__.py
utils.py
models.py
import mypackage.utils
from mypackage import models
Instal·lació de paquets
Python inclou un gestor de paquets, pip, per instal·lar biblioteques externes:
pip install numpy
pip install -r requirements.txt
És recomanable treballar dins d’un entorn virtual per aïllar les dependències de cada projecte:
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
Col·leccions
| Tipus | Mutabilitat | Ordenat | Permet duplicats |
|---|---|---|---|
list | Sí | Sí | Sí |
tuple | No | Sí | Sí |
set | Sí | No | No |
frozenset | No | No | No |
dict | Sí | Sí (>=3.7) | No (claus) |
Llistes
- Una llista és una seqüència mutable de 0 o més objectes de qualsevol tipus.
- La funció
lenretorna el nombre d’elements d’una llista. - L’operador de subíndex
[]accedeix a un element en una posició determinada.
numbers = [45, 56, 67]
print(len(numbers), numbers[2]) # 3 67
- Les llistes d’objectes comparables es poden comparar amb els operadors estàndard
==,<, etc. - La classe
listinclou molts mètodes útils per a insercions, eliminacions i cerques.
Sets
- Un
setés una col·lecció mutable de 0 o més objectes únics.
s1 = set()
for x in range(10):
s1.add(x)
s2 = {1, 2, 3}
s3 = s1.intersection(s2)
Diccionaris
- Un diccionari és una col·lecció mutable de parells clau/valor únics.
- L’operador de subíndex accedeix, afegeix o substitueix valors.
scores = {}
for i in range(1, 6):
scores["player" + str(i)] = i * 10
for key in scores:
print(key, scores[key])
Tuples
- Una
tupleés una seqüència immutable de 0 o més objectes de qualsevol tipus. - Útil per agrupar valors que no han de canviar.
- Es pot usar com a clau de diccionari, a diferència de les llistes.
empty = ()
point = (3, 4)
mixed = ("hello", 3.14, True)
print(point[0]) # 3
for item in mixed:
print(item)
Iteradors
Un iterador és un objecte que admet el recorregut d’una col·lecció. La PVM utilitza automàticament un iterador sempre que veu un bucle for.
La funció iter retorna un objecte iterador per a una col·lecció:
it = iter([1, 2, 3])
print(next(it), next(it), next(it)) # 1 2 3
Quan next ha retornat l’últim element, qualsevol crida posterior genera una excepció StopIteration.
Per recórrer tots els elements manualment:
it = iter([1, 2, 3])
while True:
try:
element = next(it)
except StopIteration:
break
Comprehensions
Les comprehensions construeixen col·leccions a partir d’iterables de manera compacta.
Llistes: [expressió for element in iterable if condició]
evens = [x for x in range(10) if x % 2 == 0]
squares = [x**2 for x in range(5)]
Conjunts: mateixa forma però amb {}
vowels = {c for c in "informatics" if c in "aeiou"}
Diccionaris: {clau: valor for element in iterable}
table = {x: x**2 for x in range(5)}
names = ["Anna", "Joan", "Pau"]
lengths = {name: len(name) for name in names}
Generadors
Un generador és una manera fàcil de crear iteradors personalitzats. En lloc d’implementar una classe amb __iter__ i __next__, usem una funció amb la instrucció yield:
def count_to(n):
i = 1
while i <= n:
yield i
i += 1
for x in count_to(3):
print(x) # 1, 2, 3
Quan yield s’executa, la funció es pausa i el valor es retorna. L’execució es reprèn en el punt on es va deixar, mantenint l’estat local.
Classes i objectes
Mètodes especials
Els mètodes especials (o dunder methods, per “double underscore”) són mètodes amb noms de la forma __nom__ que Python crida automàticament en resposta a operacions del llenguatge. Per exemple, __init__ es crida en instanciar, __str__ quan es fa print, i __eq__ quan s’usa ==. Definint-los, la classe pot participar en protocols estàndard del llenguatge com comparació, iteració o gestió de context.
Definició bàsica
Les definicions de classes tenen la forma general:
class <name>(<superclass>):
<class variables>
<methods>
La superclasse en parèntesis s’omet per a classes bàsiques.
class Student:
NUM_GRADES = 5
def __init__(self, name):
self.name = name
self.grades = []
for i in range(Student.NUM_GRADES):
self.grades.append(0)
def get_name(self): return self.name
def get_grade(self, i):
return self.grades[i - 1]
def set_grade(self, i, new_grade):
self.grades[i - 1] = new_grade
def __str__(self):
result = self.name + "\n"
result += " ".join(map(str, self.grades))
return result
Ús:
s = Student("Mary")
for i in range(1, Student.NUM_GRADES + 1):
s.set_grade(i, 100)
print(s)
Instanciació
<class name>(<arguments>)
s = Student("Mary")
La PVM crida automàticament __init__ en instanciar. L’argument self s’assigna automàticament a l’objecte nou. Les variables i paràmetres no tenen tipus; el tipus el té l’objecte al qual fan referència.
Visibilitat
Tots els elements definits dins d’una classe (variables o mètodes) són potencialment visibles. Per desaconsellar l’accés directe a variables, els implementadors de la classe en prefixen el nom amb _.
Variables d’instància i de classe
Les variables d’instància sempre porten el prefix self. S’inicialitzen en __init__. Les variables de classe es declaren directament dins de la classe, es comparteixen per totes les instàncies i es referencien amb el nom de la classe. Per convenció, s’escriuen en majúscules.
class Student:
NUM_GRADES = 5 # variable de classe
def __init__(self, name=""):
self.name = name # variable d'instància
self.grades = []
for i in range(Student.NUM_GRADES):
self.grades.append(0)
s1 = Student("Mary")
s2 = Student()
print(Student.NUM_GRADES) # 5
Mètodes d’instància
def <name>(self, <other arguments>):
<statements>
L’argument self és necessari per a un mètode d’instància. La PVM l’assigna a l’objecte receptor en la crida. Un mètode que no retorna explícitament un valor retorna None.
Com que no hi ha sobrecàrrega de mètodes, s’emula amb paràmetres per defecte o comprovant el tipus dels arguments:
def reset_grades(self, value=0):
for i in range(Student.NUM_GRADES):
if type(value) == list:
self.grades[i] = value[i]
else:
self.grades[i] = value
Ús:
s = Student("Mary")
s.reset_grades(100)
s.reset_grades()
new_grades = [85, 66, 90, 100, 73]
s.reset_grades(new_grades)
Mètodes de classe
Els mètodes de classe no accedeixen a l’estat d’instàncies concretes. Reben cls com a primer argument i s’accedeix a ells via el nom de la classe:
class Student:
@classmethod
def get_letter_grade(cls, grade):
if grade > 89: return "A"
elif grade > 79: return "B"
else: return "F"
Ús:
print(Student.get_letter_grade(95)) # A
Mètodes estàtics
Un mètode estàtic no rep ni self ni cls. S’usa per funcions utilitàries lògicament relacionades amb la classe però que no necessiten accés al seu estat:
class MathUtils:
@staticmethod
def is_even(n):
return n % 2 == 0
print(MathUtils.is_even(4)) # True
Dataclasses
El decorador @dataclass genera automàticament __init__, __repr__ i __eq__ a partir de les anotacions de tipus declarades a la classe. És el patró estàndard per a classes que principalment contenen dades:
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
p = Point(1.0, 2.0)
print(p) # Point(x=1.0, y=2.0)
print(p.x) # 1.0
print(p == Point(1.0, 2.0)) # True
Amb frozen=True, la classe es fa immutable (equivalent a una tupla amb noms):
@dataclass(frozen=True)
class Color:
r: int
g: int
b: int
Propietats
El decorador @property permet accedir a un mètode com si fos un atribut:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def area(self):
return 3.14159 * self._radius ** 2
c = Circle(5)
print(c.area) # 78.53...
Mètode __str__
La funció str converteix qualsevol objecte a la seva representació de cadena. Es pot personalitzar definint __str__. Operacions com print l’utilitzen automàticament:
class Student:
def __str__(self):
result = self.name + "\n"
result += " ".join(map(str, self.grades))
return result
Igualtat
L’operador == utilitza is per defecte, que comprova si dues variables apunten exactament al mateix objecte. Per a igualtat estructural, es defineix __eq__:
class Student:
def __eq__(self, other):
if self is other:
return True
elif type(self) != type(other):
return False
else:
return self.name == other.name
def __ne__(self, other):
return not self == other
Ús:
s1 = Student("Mary")
s2 = Student("Bill")
s3 = Student("Bill")
print(s1 == s2) # False
print(s2 == s3) # True
print(s2 is s3) # False
Comparable
Per fer que els objectes d’una classe suportin tots els operadors de comparació (<, >, <=, >=, ==, !=), es defineixen __eq__ i __lt__ i s’usa el decorador @total_ordering, que genera automàticament els operadors restants:
from functools import total_ordering
@total_ordering
class Student:
def __eq__(self, other):
if self is other: return True
elif type(self) != type(other): return False
else: return self.name == other.name
def __lt__(self, other):
return self.name < other.name
Ús:
s1 = Student("Mary")
s2 = Student("Bill")
print(s1 < s2) # False
print(s1 > s2) # True
Iteradors personalitzats
Per fer que una classe sigui iterable, es defineix __iter__ com a generador. L’exemple següent mostra una pila enllaçada que suporta iteració:
class Node:
def __init__(self, data, next):
self.data = data
self.next = next
class LinkedStack:
def __init__(self):
self.top = None
self.size = 0
def push(self, element):
self.top = Node(element, self.top)
self.size += 1
def pop(self):
element = self.top.data
self.top = self.top.next
self.size -= 1
return element
def __len__(self):
return self.size
def __iter__(self):
current = self.top
while current is not None:
yield current.data
current = current.next
Ús:
stack = LinkedStack()
stack.push(1)
stack.push(2)
stack.push(3)
for item in stack:
print(item) # 3, 2, 1
Herència
En Python es pot definir una nova classe que reutilitza el codi d’una altra. La nova classe n’és una subclasse i hereta tots els atributs i mètodes de la classe pare.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return ""
def __str__(self):
return f"{self.name} says: {self.speak()}"
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
Ús:
animals = [Dog("Rex"), Cat("Whiskers"), Dog("Buddy")]
for animal in animals:
print(animal)
La subclasse pot cridar el constructor del pare amb super():
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
def speak(self):
return "Woof!"
Classes abstractes
Quan diverses classes contenen codi comú, es pot factoritzar en una classe abstracta: una classe que no s’instancia directament, sinó que serveix de base comuna.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
def __str__(self):
return f"{type(self).__name__} with area {self.area():.2f}"
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
Ús:
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape)
El decorador @abstractmethod obliga les subclasses a implementar el mètode. Intentar instanciar directament Shape genera un error.
Gestió d’errors
Python permet capturar i gestionar errors amb blocs try i except:
try:
x = int(input("Enter a number: "))
result = 10 / x
except ValueError:
print("That was not an integer.")
except ZeroDivisionError:
print("Cannot divide by zero.")
finally:
print("This always runs.")
try: conté el codi que pot generar una excepció.except: captura un error específic i executa el codi corresponent.finally: (opcional) s’executa sempre, hagi passat o no una excepció.
Es pot capturar l’excepció en una variable amb as:
try:
1 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
Es poden provocar errors manualment amb raise:
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero.")
return a / b
Tipus d’excepcions comunes:
| Excepció | Quan apareix |
|---|---|
ValueError | Conversió incorrecta de tipus (int("abc")) |
ZeroDivisionError | Divisió entre zero |
TypeError | Operacions entre tipus incompatibles |
IndexError | Índex fora de rang en una seqüència |
KeyError | Clau inexistent en un diccionari |
FileNotFoundError | Arxiu inexistent |
Context managers
Un gestor de context defineix accions a fer abans i després d’un bloc de codi. S’utilitzen habitualment per gestionar recursos que s’han d’obrir i tancar.
with open("notes.txt", "r") as file:
content = file.read()
open(...)obre el fitxer.- El fitxer es tanca automàticament en sortir del bloc, fins i tot si hi ha un error.
- Això evita haver d’escriure
file.close()manualment.
Es poden definir gestors de context propis amb dos mètodes especials:
__enter__: s’executa al començar el bloc.__exit__: s’executa al final, fins i tot si hi ha excepcions.
Anotacions de tipus
Python permet indicar els tipus d’arguments i valors retornats. Les anotacions no es comproven en temps d’execució, però ajuden a documentar el codi i milloren la detecció d’errors per eines com mypy o editors com VSCode.
def greet(name: str, age: int) -> str:
return f"Hello, {name}. You are {age} years old."
Des de Python 3.10, els tipus compostos s’escriuen directament amb tipus natius i l’operador |:
| Sintaxi | Descripció |
|---|---|
list[T] | Llista d’elements del tipus T |
dict[K, V] | Diccionari amb claus de tipus K i valors V |
T | None | Valor que pot ser de tipus T o None |
tuple[T1, T2] | Tupla amb elements de tipus T1, T2, etc. |
T1 | T2 | Valor que pot ser de tipus T1 o T2 |
typing.Any | Qualsevol tipus (requereix import) |
def sum_list(nums: list[int]) -> int:
return sum(nums)
def find(lst: list[int], value: int) -> int | None:
if value in lst:
return value
return None
Les formes antigues del mòdul typing (List[T], Dict[K,V], Optional[T], Union[T1, T2]) continuen funcionant però es consideren llegat i no s’han d’usar en codi nou.
Python idiomàtic
Aquesta secció recull construccions i funcions habituals de Python.
-
enumerate(iterable)→ índex i valor alhorafor i, value in enumerate(["a", "b", "c"]): print(i, value) # 0 a / 1 b / 2 c -
zip→ agrupar iterables en paral·lelnames = ["A", "B", "C"] scores = [7, 8, 9] for name, score in zip(names, scores): print(name, score) -
all,any→ comprovar condicions sobre col·leccionsscores = [7, 8, 9] print(all(n > 5 for n in scores)) # True print(any(n == 10 for n in scores)) # False -
sorted(iterable, key=...)→ nova llista ordenada sense modificar l’originalwords = ["car", "water", "moon"] print(sorted(words, key=len)) # ['car', 'moon', 'water'] -
Desempaquetament múltiple
a, b = (1, 2) a, *rest, b = [1, 2, 3, 4, 5] # a=1, rest=[2,3,4], b=5 -
Slicing avançat (essencial per arrays i tensors)
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(lst[2:7]) # [2, 3, 4, 5, 6] print(lst[::2]) # [0, 2, 4, 6, 8] print(lst[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] -
map,filter,reduce→ programació funcionalfrom functools import reduce nums = [1, 2, 3, 4] squares = list(map(lambda x: x**2, nums)) # [1, 4, 9, 16] evens = list(filter(lambda x: x % 2 == 0, nums)) # [2, 4] total = reduce(lambda x, y: x + y, nums) # 10 -
Gestió de paths amb
pathlibfrom pathlib import Path file = Path("data") / "train.csv" if file.exists(): content = file.read_text() -
Lectura de fitxers amb
withwith open("data.txt") as f: for line in f: print(line.strip()) -
Mòdul
csvimport csv with open("data.csv") as f: reader = csv.reader(f) for row in reader: print(row) -
Walrus operator (Python 3.8+)
while (line := f.readline()): process(line)