Best fit
- Patrones idiomáticos de Python, estándares PEP 8, type hints y buenas prácticas para construir aplicaciones Python robustas, eficientes y mantenibles.
affaan-m/ECC
Patrones idiomáticos de Python, estándares PEP 8, type hints y buenas prácticas para construir aplicaciones Python robustas, eficientes y mantenibles.
npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/python-patterns"Source checked Jul 28, 2026·Refresh due Oct 26, 2026
Reorganized from the pinned upstream SKILL.md
According to the pinned SKILL.md from affaan-m/ECC: Patrones idiomáticos de Python y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.
npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/python-patterns"Best fit
Bring this context
Expected outputs
Key source sections
Sections are extracted automatically from the pinned SKILL.md and link back to the source.
python import concurrent.futures
Escribir código Python nuevo
Python prioriza la legibilidad. El código debe ser obvio y fácil de entender.
Python prioriza la legibilidad. El código debe ser obvio y fácil de entender.
def getactiveusers(users: list[User]) - list[User]: """Retorna solo los usuarios activos de la lista proporcionada.""" return [user for user in users if user.isactive]
SkillSignal prompt templates
These prompts were written by SkillSignal from the source structure; they are not upstream text.
Task-start prompt
Confirm source fit, inputs, and outputs before acting.
Use python-patterns to help me with: [specific task]. Context: [files, data, or background]. Constraints: [environment, scope, and prohibited actions]. Before acting, check the pinned SKILL.md and explain which sections apply, what inputs are still missing, and what you will deliver.
Source-guided execution
Make the Agent explicitly follow the key extracted sections.
Apply the pinned python-patterns source to [task]. Pay particular attention to these source sections: “Cada llamada a process() imprime el conteo de llamadas”, “Cuándo Activar”, “Principios Fundamentales”, “1. La Legibilidad Cuenta”, “Bien: Claro y legible”. Preserve the important decision at each step. Mark facts not covered by the source as “needs confirmation” instead of inventing them. Then verify the result against my acceptance criteria: [criteria].
Result-review prompt
Check omissions, permissions, and source drift before delivery.
Review the current python-patterns result: (1) does it satisfy the original task; (2) were any applicable steps or limits in the pinned SKILL.md missed; (3) did it perform any unauthorized file, command, network, or data action; and (4) which conclusions remain unverified? List issues first, then fix only what the source or user authorization supports.
Output checklist
The task matches the purpose documented in the SKILL.md.
The source section “Cada llamada a process() imprime el conteo de llamadas” has been checked.
The source section “Cuándo Activar” has been checked.
The source section “Principios Fundamentales” has been checked.
The source section “1. La Legibilidad Cuenta” has been checked.
Inputs, constraints, and acceptance criteria are explicit.
Unverified facts, compatibility, and outcome claims are clearly marked.
Any file, command, network, or data action has been reviewed.
Choose a different workflow
Python-specific design patterns and best practices including protocols, dataclasses, context managers, decorators, async/await, type hints, and package organization. Use when working with Python code to apply Pythonic patterns.
A separate implementation from affaan-m/ECC; compare its source, maintenance signals, and permission requirements.
Open source detailPythonic idiomlar, PEP 8 standartları, type hint'ler ve sağlam, verimli ve bakımı kolay Python uygulamaları oluşturmak için en iyi uygulamalar.
A separate implementation from affaan-m/ECC; compare its source, maintenance signals, and permission requirements.
Open source detailPythonic idioms, PEP 8 standards, type hints, and best practices for building robust, efficient, and maintainable Python applications.
A separate implementation from affaan-m/ECC; compare its source, maintenance signals, and permission requirements.
Open source detailFAQ
Patrones idiomáticos de Python y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.
The catalog detected this source-specific install command: npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/python-patterns". Inspect the command and pinned source before running it.
No dedicated Agent platform is declared in the pinned source record.
Quality breakdown
Based on traceable docs and repository signals; stars are not treated as quality.
Compare before choosing
These links are selected from shared tasks, functions, stacks, platforms, and same-name variants. Compare the source owner, documentation, permissions, and maintenance signals.
Python-specific design patterns and best practices including protocols, dataclasses, context managers, decorators, async/await, type hints, and package organization. Use when working with Python code to apply Pythonic patterns.
Pythonic idiomlar, PEP 8 standartları, type hint'ler ve sağlam, verimli ve bakımı kolay Python uygulamaları oluşturmak için en iyi uygulamalar.
Pythonic idioms, PEP 8 standards, type hints, and best practices for building robust, efficient, and maintainable Python applications.
Pythonic 惯用法、PEP 8 标准、类型提示以及构建稳健、高效且可维护的 Python 应用程序的最佳实践。
Pythonic イディオム、PEP 8標準、型ヒント、堅牢で効率的かつ保守可能なPythonアプリケーションを構築するためのベストプラクティス。
Patrones idiomáticos de Python y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.
Python prioriza la legibilidad. El código debe ser obvio y fácil de entender.
# Bien: Claro y legible
def get_active_users(users: list[User]) -> list[User]:
"""Retorna solo los usuarios activos de la lista proporcionada."""
return [user for user in users if user.is_active]
# Mal: Inteligente pero confuso
def get_active_users(u):
return [x for x in u if x.a]
Evitar la magia; ser claro sobre lo que hace el código.
# Bien: Configuración explícita
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Mal: Efectos secundarios ocultos
import some_module
some_module.setup() # ¿Qué hace esto?
Python prefiere el manejo de excepciones sobre verificar condiciones.
# Bien: Estilo EAFP
def get_value(dictionary: dict, key: str) -> Any:
try:
return dictionary[key]
except KeyError:
return default_value
# Mal: Estilo LBYL (Look Before You Leap)
def get_value(dictionary: dict, key: str) -> Any:
if key in dictionary:
return dictionary[key]
else:
return default_value
from typing import Optional, List, Dict, Any
def process_user(
user_id: str,
data: Dict[str, Any],
active: bool = True
) -> Optional[User]:
"""Procesa un usuario y retorna el User actualizado o None."""
if not active:
return None
return User(user_id, data)
# Python 3.9+ - Usar tipos built-in
def process_items(items: list[str]) -> dict[str, int]:
return {item: len(item) for item in items}
# Python 3.8 y anteriores - Usar módulo typing
from typing import List, Dict
def process_items(items: List[str]) -> Dict[str, int]:
return {item: len(item) for item in items}
from typing import TypeVar, Union
# Type alias para tipos complejos
JSON = Union[dict[str, Any], list[Any], str, int, float, bool, None]
def parse_json(data: str) -> JSON:
return json.loads(data)
# Tipos genéricos
T = TypeVar('T')
def first(items: list[T]) -> T | None:
"""Retorna el primer elemento o None si la lista está vacía."""
return items[0] if items else None
from typing import Protocol
class Renderable(Protocol):
def render(self) -> str:
"""Renderiza el objeto a una cadena."""
def render_all(items: list[Renderable]) -> str:
"""Renderiza todos los elementos que implementan el protocolo Renderable."""
return "\n".join(item.render() for item in items)
# Bien: Capturar excepciones específicas
def load_config(path: str) -> Config:
try:
with open(path) as f:
return Config.from_json(f.read())
except FileNotFoundError as e:
raise ConfigError(f"Archivo de config no encontrado: {path}") from e
except json.JSONDecodeError as e:
raise ConfigError(f"JSON inválido en config: {path}") from e
# Mal: except desnudo
def load_config(path: str) -> Config:
try:
with open(path) as f:
return Config.from_json(f.read())
except:
return None # ¡Fallo silencioso!
def process_data(data: str) -> Result:
try:
parsed = json.loads(data)
except json.JSONDecodeError as e:
# Encadenar excepciones para preservar el traceback
raise ValueError(f"Error al parsear datos: {data}") from e
class AppError(Exception):
"""Excepción base para todos los errores de la aplicación."""
pass
class ValidationError(AppError):
"""Se lanza cuando falla la validación de entrada."""
pass
class NotFoundError(AppError):
"""Se lanza cuando no se encuentra un recurso solicitado."""
pass
# Uso
def get_user(user_id: str) -> User:
user = db.find_user(user_id)
if not user:
raise NotFoundError(f"Usuario no encontrado: {user_id}")
return user
# Bien: Usar context managers
def process_file(path: str) -> str:
with open(path, 'r') as f:
return f.read()
# Mal: Gestión manual de recursos
def process_file(path: str) -> str:
f = open(path, 'r')
try:
return f.read()
finally:
f.close()
from contextlib import contextmanager
@contextmanager
def timer(name: str):
"""Context manager para medir el tiempo de un bloque de código."""
start = time.perf_counter()
yield
elapsed = time.perf_counter() - start
print(f"{name} tardó {elapsed:.4f} segundos")
# Uso
with timer("procesamiento de datos"):
process_large_dataset()
class DatabaseTransaction:
def __init__(self, connection):
self.connection = connection
def __enter__(self):
self.connection.begin_transaction()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.connection.commit()
else:
self.connection.rollback()
return False # No suprimir excepciones
# Uso
with DatabaseTransaction(conn):
user = conn.create_user(user_data)
conn.create_profile(user.id, profile_data)
# Bien: List comprehension para transformaciones simples
names = [user.name for user in users if user.is_active]
# Mal: Loop manual
names = []
for user in users:
if user.is_active:
names.append(user.name)
# Las comprehensions complejas deben expandirse
# Mal: Demasiado complejo
result = [x * 2 for x in items if x > 0 if x % 2 == 0]
# Bien: Usar una función generadora
def filter_and_transform(items: Iterable[int]) -> list[int]:
result = []
for x in items:
if x > 0 and x % 2 == 0:
result.append(x * 2)
return result
# Bien: Generador para evaluación lazy
total = sum(x * x for x in range(1_000_000))
# Mal: Crea una lista intermedia grande
total = sum([x * x for x in range(1_000_000)])
def read_large_file(path: str) -> Iterator[str]:
"""Lee un archivo grande línea por línea."""
with open(path) as f:
for line in f:
yield line.strip()
# Uso
for line in read_large_file("huge.txt"):
process(line)
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class User:
"""Entidad de usuario con __init__, __repr__ y __eq__ automáticos."""
id: str
name: str
email: str
created_at: datetime = field(default_factory=datetime.now)
is_active: bool = True
# Uso
user = User(
id="123",
name="Alice",
email="alice@example.com"
)
@dataclass
class User:
email: str
age: int
def __post_init__(self):
# Validar formato de email
if "@" not in self.email:
raise ValueError(f"Email inválido: {self.email}")
# Validar rango de edad
if self.age < 0 or self.age > 150:
raise ValueError(f"Edad inválida: {self.age}")
from typing import NamedTuple
class Point(NamedTuple):
"""Punto 2D inmutable."""
x: float
y: float
def distance(self, other: 'Point') -> float:
return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
# Uso
p1 = Point(0, 0)
p2 = Point(3, 4)
print(p1.distance(p2)) # 5.0
import functools
import time
def timer(func: Callable) -> Callable:
"""Decorador para medir el tiempo de ejecución de una función."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} tardó {elapsed:.4f}s")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
# slow_function() imprime: slow_function tardó 1.0012s
def repeat(times: int):
"""Decorador para repetir una función múltiples veces."""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
@repeat(times=3)
def greet(name: str) -> str:
return f"¡Hola, {name}!"
# greet("Alice") retorna ["¡Hola, Alice!", "¡Hola, Alice!", "¡Hola, Alice!"]
class CountCalls:
"""Decorador que cuenta cuántas veces se llama una función."""
def __init__(self, func: Callable):
functools.update_wrapper(self, func)
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} ha sido llamada {self.count} veces")
return self.func(*args, **kwargs)
@CountCalls
def process():
pass
# Cada llamada a process() imprime el conteo de llamadas
import concurrent.futures
def fetch_url(url: str) -> str:
"""Obtiene una URL (operación I/O-bound)."""
import urllib.request
with urllib.request.urlopen(url) as response:
return response.read().decode()
def fetch_all_urls(urls: list[str]) -> dict[str, str]:
"""Obtiene múltiples URLs concurrentemente usando hilos."""
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
future_to_url = {executor.submit(fetch_url, url): url for url in urls}
results = {}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
results[url] = future.result()
except Exception as e:
results[url] = f"Error: {e}"
return results
def process_data(data: list[int]) -> int:
"""Cómputo intensivo de CPU."""
return sum(x ** 2 for x in data)
def process_all(datasets: list[list[int]]) -> list[int]:
"""Procesa múltiples datasets usando múltiples procesos."""
with concurrent.futures.ProcessPoolExecutor() as executor:
results = list(executor.map(process_data, datasets))
return results
import asyncio
async def fetch_async(url: str) -> str:
"""Obtiene una URL de forma asíncrona."""
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def fetch_all(urls: list[str]) -> dict[str, str]:
"""Obtiene múltiples URLs concurrentemente."""
tasks = [fetch_async(url) for url in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
return dict(zip(urls, results))
myproject/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ ├── main.py
│ ├── api/
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ └── utils/
│ ├── __init__.py
│ └── helpers.py
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_api.py
│ └── test_models.py
├── pyproject.toml
├── README.md
└── .gitignore
# Bien: Orden de importación - stdlib, terceros, locales
import os
import sys
from pathlib import Path
import requests
from fastapi import FastAPI
from mypackage.models import User
from mypackage.utils import format_name
# Bien: Usar isort para ordenar importaciones automáticamente
# mypackage/__init__.py
"""mypackage - Un paquete Python de ejemplo."""
__version__ = "1.0.0"
# Exportar clases/funciones principales al nivel del paquete
from mypackage.models import User, Post
from mypackage.utils import format_name
__all__ = ["User", "Post", "format_name"]
# Mal: La clase regular usa __dict__ (más memoria)
class Point:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
# Bien: __slots__ reduce el uso de memoria
class Point:
__slots__ = ['x', 'y']
def __init__(self, x: float, y: float):
self.x = x
self.y = y
# Mal: Retorna la lista completa en memoria
def read_lines(path: str) -> list[str]:
with open(path) as f:
return [line.strip() for line in f]
# Bien: Produce líneas una a la vez
def read_lines(path: str) -> Iterator[str]:
with open(path) as f:
for line in f:
yield line.strip()
# Mal: O(n²) debido a la inmutabilidad de cadenas
result = ""
for item in items:
result += str(item)
# Bien: O(n) usando join
result = "".join(str(item) for item in items)
# Formateo de código
black .
isort .
# Linting
ruff check .
pylint mypackage/
# Verificación de tipos
mypy .
# Pruebas
pytest --cov=mypackage --cov-report=html
# Escaneo de seguridad
bandit -r .
# Gestión de dependencias
pip-audit
safety check
[project]
name = "mypackage"
version = "1.0.0"
requires-python = ">=3.9"
dependencies = [
"requests>=2.31.0",
"pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"ruff>=0.1.0",
"mypy>=1.5.0",
]
[tool.black]
line-length = 88
target-version = ['py39']
[tool.ruff]
line-length = 88
select = ["E", "F", "I", "N", "W"]
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=mypackage --cov-report=term-missing"
| Patrón | Descripción |
|---|---|
| EAFP | Es Más Fácil Pedir Perdón que Permiso |
| Context managers | Usar with para gestión de recursos |
| List comprehensions | Para transformaciones simples |
| Generadores | Para evaluación lazy y datasets grandes |
| Type hints | Anotar las firmas de funciones |
| Dataclasses | Para contenedores de datos con métodos auto-generados |
__slots__ | Para optimización de memoria |
| f-strings | Para formateo de cadenas (Python 3.6+) |
pathlib.Path | Para operaciones de rutas (Python 3.4+) |
enumerate | Para pares índice-elemento en loops |
# Mal: Argumentos por defecto mutables
def append_to(item, items=[]):
items.append(item)
return items
# Bien: Usar None y crear nueva lista
def append_to(item, items=None):
if items is None:
items = []
items.append(item)
return items
# Mal: Verificar tipo con type()
if type(obj) == list:
process(obj)
# Bien: Usar isinstance
if isinstance(obj, list):
process(obj)
# Mal: Comparar con None usando ==
if value == None:
process()
# Bien: Usar is
if value is None:
process()
# Mal: from module import *
from os.path import *
# Bien: Importaciones explícitas
from os.path import join, exists
# Mal: except desnudo
try:
risky_operation()
except:
pass
# Bien: Excepción específica
try:
risky_operation()
except SpecificError as e:
logger.error(f"Operación fallida: {e}")
Recuerda: El código Python debe ser legible, explícito y seguir el principio de la menor sorpresa. Ante la duda, prioriza la claridad sobre la ingeniosidad.