.. 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
-P
en 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