.. toctree:: :glob: :hidden: *
.. revealjs_section::
:data-transition: zoom
.. revealjs_section::
:data-transition: convex
>>> import datetime
>>> import humanize
>>> delta = datetime.datetime(2022, 10, 27) - datetime.datetime(2020, 3, 4)
>>> humanize.i18n.activate("es_ES")
>>> print(repr(humanize.precisedelta(delta)))
"2 años, 7 meses y 23 días"Programando en Python desde 2006 |
.. revealjs_section::
:data-transition: concave
- PEP 654: Exception Groups y except*.
- PEP 678: Enriquecer excepciones con notas.
- PEP 680: tomllib.
- PEP 657: Mejoras en las indicaciones de error en los tracebacks.
- Opción
-Pen la línea de comandos y variable de entornoPYTHONSAFEPATH. - PEP 646: Variadic Generics.
- PEP 655: TypedDict Required/NotRequired.
- PEP 673: Tipo Self.
- PEP 675: Tipo de cadena literal arbitraria
- PEP 681: Data Class Transforms
- Módulos obsoletos (PEP 594), Py_UNICODE API eliminada (PEP 624) y macros convertidas a funciones estáticas en línea (PEP 670).
.. revealjs_section::
:data-transition: zoom
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 1-2,7,12|11-14|5-7|13-14
class NameError(Exception):
pass
def validate_name(value: str) -> None:
if not value.istitle():
raise NameError("El nombre debe empezar por mayúscula.")
form = {"name": "nekmo"}
try:
validate_name(form["name"])
except NameError as err:
print(err) # Salta el error
.. revealjs_break::
:notitle:
:data-transition: zoom
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 13,17|8-10,14,19|21|22-23
from typing import Iterable, Tuple, Dict, Callable
class NumberError(Exception):
pass
def validate_age(value: str) -> None:
if not value.isdigit():
raise NumberError("La edad debe ser un valor numérico.")
form = {"name": "nekmo", "age": "diez"}
form_validations = [("name", validate_name), ("age", validate_age)]
exceptions = []
for form_key, input_validation in input_validations:
try:
input_validation(form[form_key])
except Exception as err:
exceptions.append(value)
if exceptions:
raise ExceptionGroup("errors message", exceptions)
.. revealjs_break::
:notitle:
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 1-8|3-5|6-8
try:
read_inputs()
except* NameError as eg:
# Si hay errores NameError esto se llama
print(f"Errores en el nombre: {eg.exceptions}")
except* NumberError as eg:
# Y si hay errores NumberError, esto también
print(f"Errores numéricos: {eg.exceptions}")
.. revealjs_break::
:notitle:
raise ExceptionGroup("nested",
[
ValueError(654),
ExceptionGroup("imports",
[
ImportError("no_such_module"),
ModuleNotFoundError("another_module"),
]
),
TypeError("int"),
].. revealjs_section::
:data-background-color: #000000
:data-background-image: _static/applause.gif
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 2|3|4|5
try:
raise TypeError('bad type')
except Exception as e:
e.add_note('¡Ah, ah, ah! ¡No has dicho la palabra mágica!')
raise
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 1-4|4
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: bad type
¡Ah, ah, ah! ¡No has dicho la palabra mágica!
.. revealjs_break::
:notitle:
+ Exception Group Traceback (most recent call last):
| File "test.py", line 4, in test
| def test(x):
|
| File "hypothesis/core.py", line 1202, in wrapped_test
| raise the_error_hypothesis_found
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ExceptionGroup: Hypothesis found 2 distinct failures.
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "test.py", line 6, in test
| assert x > 0
| ^^^^^^^^^^^^
| AssertionError: assert -1 > 0
|
| Falsifying example: test(
| x=-1,
| )
+---------------- 2 ----------------
| Traceback (most recent call last):
| File "test.py", line 5, in test
| assert x < 0
| ^^^^^^^^^^^^
| AssertionError: assert 0 < 0
|
| Falsifying example: test(
| x=0,
| )
+------------------------------------.. revealjs_break::
:notitle:
:data-auto-animate:
.. revealjs-code-block:: python
:data-line-numbers: 5-6
Traceback (most recent call last):
File "distance.py", line 11, in <module>
print(manhattan_distance(p1, p2))
File "distance.py", line 6, in manhattan_distance
return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
AttributeError: 'NoneType' object has no attribute 'x'
.. revealjs_break::
:notitle:
:data-auto-animate:
.. revealjs-code-block:: python
:data-line-numbers: 4,6-8
Traceback (most recent call last):
File "distance.py", line 11, in <module>
print(manhattan_distance(p1, p2))
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "distance.py", line 6, in manhattan_distance
return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 11-13
Traceback (most recent call last):
File "query.py", line 37, in <module>
magic_arithmetic('foo')
File "query.py", line 18, in magic_arithmetic
return add_counts(x) / 25
^^^^^^^^^^^^^
File "query.py", line 24, in add_counts
return 25 + query_user(user1) + query_user(user2)
^^^^^^^^^^^^^^^^^
File "query.py", line 32, in query_user
return 1 + query_count(db, response['a']['b']['c']['user'], retry=True)
~~~~~~~~~~~~~~~~~~^^^^^
TypeError: 'NoneType' object is not subscriptable
.. revealjs_break::
:notitle:
.. revealjs_break::
:notitle:
# This is a TOML document
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend".. revealjs_break::
:notitle:
import tomllib
with open("fichero.toml") as f:
tomllib.load(f).. revealjs_break::
:notitle:
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 9-14|5,18|10-11,18-19|13-14,18,21|1-21
from typing import Tuple, Generic, TypeVarTuple, TypeVar
T = TypeVar('T')
Ts = TypeVarTuple('Ts') # Esta es la novedad
# Aquí usamos el TypeVarTuple como definición para el tipo
class Array(Generic[*Ts]):
def multiply(self, x: int) -> Tuple[*Ts]: # Y aquí como return
...
def add_dimension(self, t: T) -> Tuple[T, *Ts]:
...
# Ts en este caso será [float, int, str]
my_array: Array[float, int, str] = Array()
my_array.multiply(2) # El tipo devuelto será Tuple[float, int, str]
# El tipo devuelto será Tuple[str, float, int, str]
my_array.add_dimension("spam")
.. revealjs_break::
:notitle:
:data-background-color: #000000
:data-background-image: _static/confused.gif
.. revealjs_break::
:notitle:
:data-auto-animate:
.. revealjs-code-block:: python
:data-line-numbers: 1-9|4
from typing import TypedDict
class Person(TypedDict, total=False):
name: str # Queremos que sea obligatorio pero no lo es
surname: str # Queremos que sea obligatorio pero no lo es
age: int
person: Person = {"name": "Juan", "surname": "Luna"}
.. revealjs_break::
:notitle:
:data-auto-animate:
.. revealjs-code-block:: python
:data-line-numbers: 4-10|4,9
from typing import TypedDict
class PersonRequired(TypedDict, total=True):
name: str
surname: str
class Person(PersonRequired, total=False):
age: int
person: Person = {"name": "Juan", "surname": "Luna"}
.. revealjs_break::
:notitle:
:data-auto-animate:
.. revealjs-code-block:: python
:data-line-numbers: 1-10|7
from typing import NotRequired, Required, TypedDict
class Person(TypedDict): # total=True por defecto
name: str
surname: str
age: NotRequired[int] # age no será requerido por el NotRequired[]
person: Person = {"name": "Juan", "surname": "Luna"}
.. revealjs_break::
:notitle:
:data-transition: zoom
.. revealjs-code-block:: python
:data-line-numbers: 1-10|4|5-6
from typing import NotRequired, Required, TypedDict
class Person(TypedDict, total=False):
name: Required[str]
surname: Required[str]
age: int
person: Person = {"name": "Juan", "surname": "Luna"}
.. revealjs_break::
:notitle:
:data-background-color: #000000
:data-background-image: _static/thumb.gif
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 10-11
from typing import Self
class Customer:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def __copy__(self) -> Self:
return self.__class__(self.name, self.age)
.. revealjs_break::
:notitle:
.. revealjs-code-block:: python
:data-line-numbers: 1-11|8|11
from typing import LiteralString, Iterable, Any
def execute(sql: LiteralString, *params: Iterable[Any]):
...
# Esta línea validará, porque pasamos los parámetros de forma segura
execute("SELECT * FROM data WHERE user_id = ?", [123])
# Esta línea dará error, porque se modifica el string de entrada previamente
execute(f"SELECT * FROM data WHERE user_id = {user_id}") # MEEH! Error.
.. revealjs_section::
:data-background-color: #000000
:data-background-image: _static/security.gif
.. revealjs_break::
:notitle:
# La clase ``ModelBase`` está definida en la biblioteca.
@typing.dataclass_transform()
class ModelBase: ...
# La clase ``ModelBase`` puede ser usado para crear nuevos modelos,
# similar a como se hace en estos frameworks.
class CustomerModel(ModelBase):
id: int.. revealjs_break::
:notitle:
def dataclass_transform(
*,
eq_default: bool = True,
order_default: bool = False,
kw_only_default: bool = False,
field_specifiers: tuple[type | Callable[..., Any], ...] = (),
**kwargs: Any,
) -> Callable[[_T], _T]: ..... revealjs-fragments::
* Nuevo argumento ``-P`` en la línea de comandos y variable de entorno ``PYTHONSAFEPATH`` para
**evitar ejecutar código inseguro**.
* **PEP 594**: Eliminar módulos muertos de la librería estándar (deprecated, a eliminar en 3.13).
* **PEP 624**: Eliminadas las APIs de codificación de Py_UNICODE.
* **PEP 670**: Convertir macros a funciones en la API en C de Python.
* **¡Y es más rápido!** (10-60% respecto Python 3.10).
https://docs.python.org/3.11/whatsnew/3.11.html
.. revealjs_section::
:data-transition: convex
.. revealjs-fragments::
**¡¡Ya disponible!!**
https://www.build-python-from-source.com/
.. revealjs_section::
:data-background-color: #ffffff
:data-background-size: contain
:data-background-image: _static/sam.png
:data-transition: zoom
.. revealjs-fragments::
**Referencias**
* `Qué hay de nuevo en Python 3.11 (doc oficial) <https://docs.python.org/3.11/whatsnew/3.11.html>`_.
* `Preview exception groups (Real Python) <https://realpython.com/python311-exception-groups/>`_.
* `Python variadic generics (Anthony Explains) <https://www.youtube.com/watch?v=hAj3nGzeSiQ>`_.
.. revealjs_section::
:data-transition: zoom
github:Nekmo/python311-presentacion
.. revealjs_break::
:data-background-color: #ffffff
:data-background-size: contain
:data-background-image: _static/qr.png
:notitle:
- Sitio web: nekmo.com
- Email: contacto@nekmo.com
- Twitter: @nekmocom
- Telegram: @nekmo
- Jabber: nekmo@nekmo.org



