Cómo usar una lista de reglas de Python
Las páginas de esta sección - una lista maestra de 50 elementos, más bancos de 30 elementos para código asíncrono, seguridad y trabajo de datos/ML, más un banco de 40 elementos para diseño de API - pueden parecer, a primera vista, el mismo contenido dividido en listas de diferentes tamaños. No lo son. Cada una existe porque un dominio específico de trabajo con Python tiene modos de fallo que la lista general no puede cubrir sin volverse demasiado larga para usar o demasiado vaga para aplicar, y la división en sí misma es una decisión de diseño que vale la pena entender antes de usar cualquier lista individual.
Esta página explica ese diseño: por qué las reglas se agrupan de la manera en que lo hacen, qué separa una regla que puedes poner en un linter de una que solo puedes poner en una lista de verificación de revisión de código, y cómo una lista de reglas está destinada a funcionar día a día en lugar de permanecer sin leer en una wiki. No reitera las reglas en sí mismas: 50 reglas de Python que todo especialista debe seguir y los bancos específicos del dominio ya lo hacen.
Resumen
- Una lista de reglas es un conjunto codificado de valores predeterminados del equipo, dividido por dominio porque diferentes áreas de trabajo con Python (async, seguridad, datos/ML, diseño de API) fallan de maneras diferentes y específicas.
- Por qué Importa: Usada correctamente, una lista de reglas elimina el debate repetitivo de la revisión de código; usada como dogma, produce fatiga de alertas o reglas aplicadas donde no encajan en el contexto.
- Conceptos Clave: regla aplicable, regla de decisión de juicio, banco específico del dominio, numeración de reglas como navegación, excepción documentada.
- Cuándo Usar Este Modelo: Decidir qué lista se aplica a un fragmento de código, configurar reglas de linter/CI a partir de una lista, o manejar un desacuerdo sobre si una regla se aplica en un caso específico.
- Limitaciones / Compensaciones: Una lista de reglas captura lo que un equipo ya sabe que debe vigilar; no puede anticipar todos los nuevos modos de fallo, y tratarla como completa es en sí mismo un riesgo.
- Temas Relacionados: configuración de análisis estático, estándares de revisión de código, documentación de incorporación, registros de decisiones de arquitectura.
Fundamentos
Una regla, en el sentido que esta sección usa la palabra, es un valor predeterminado codificado: una decisión que un equipo ya ha tomado una vez, en general, para que no tenga que ser re-debatida en cada pull request.
Eso es diferente de una ley: una regla puede ser anulada cuando el contexto específico lo requiere, siempre que la anulación sea deliberada y visible, no ignorada silenciosamente.
La división más clara dentro de cualquier lista aquí es entre reglas que son mecánicamente aplicables y reglas que requieren juicio.
Una regla aplicable tiene una herramienta que puede verificarla automáticamente: ruff detectando una importación no utilizada, mypy detectando una anotación de tipo faltante, un hook de pre-commit detectando un patrón de secreto codificado en texto plano: de modo que un revisor humano nunca necesite verificarla manualmente.
Una regla de decisión de juicio no puede ser verificada por una herramienta en absoluto: "excepciones específicas sobre except: pass genérico" requiere comprender qué está tratando de hacer realmente el código, y "inyección de dependencias sobre globales" requiere comprender el diseño, no solo escanear la sintaxis.
Ambos tipos de reglas pertenecen a una lista útil, pero confundirlas es un error común: esperar que un linter aplique una decisión de juicio lleva a la decepción, y esperar que un revisor humano detecte de manera confiable lo que un linter debería haber detectado lleva a la inconsistencia.
Mecánicas e Interacciones
La estructura de esta sección: una lista maestra general más bancos de dominio separados, existe porque los modos de fallo específicos del dominio no encajan limpiamente en una sola lista plana sin inflarla más allá de la utilidad o forzar reglas no relacionadas a compartir la misma sección.
50 reglas de Python que todo especialista debe seguir cubre lo que se aplica ampliamente: estilo, tipos, estructura, pruebas y seguridad básica, organizado en grupos numerados (estilo 1-10, tipos 11-20, y así sucesivamente).
Esa numeración es una ayuda de navegación, no un orden de prioridad: la regla 45 (SQL parametrizado) no es menos importante que la regla 5 (f-strings) solo porque aparece más tarde en la lista; los grupos existen para que un lector pueda saltar a la sección relevante, no para que las reglas puedan clasificarse por número.
30 reglas asíncronas, 30 reglas de seguridad para Python y 30 reglas de código de datos/ML existen como bancos separados porque cada dominio tiene trampas invisibles desde una perspectiva general de Python: asyncio tiene puntos débiles específicos en torno a llamadas bloqueantes dentro de corrutinas y await olvidados que no existen en el código síncrono en absoluto, la seguridad tiene un modelo de amenaza completo con forma de OWASP que una guía de estilo general nunca fue diseñada para cubrir, y las canalizaciones de datos/ML tienen modos de fallo de reproducibilidad y fuga de datos que no se parecen en nada a un error típico de servicio web.
40 reglas de diseño de API (FastAPI/Django/Flask) es específico del dominio de la misma manera, limitado a la capa del framework donde residen los contratos de solicitud/respuesta, el control de versiones y la consistencia de la forma de los errores, preocupaciones que la lista general solo toca de pasada.
# Una regla hecha mecánicamente aplicable, y una que no puede serlo:
# la regla B008 de ruff detecta esto automáticamente:
def handler(items=[]): # valor predeterminado mutable - marcado por análisis estático
...
# pero ninguna herramienta puede verificar esto:
# "separar la lógica de dominio de las E/S para que sea testeable sin mocks"
# - ese es un juicio de arquitectura que un revisor tiene que hacer leyendo el código.La conclusión de esa división es práctica: al adoptar una lista, mapea cada regla aplicable a un código ruff select, configuración de mypy o hook de pre-commit real, y deja las reglas de decisión de juicio para las listas de verificación de revisión y las conversaciones de incorporación; intentar forzar el segundo tipo en la automatización produce falsas confianzas o reglas sobre las que nadie puede articular por qué existen.
Consideraciones y Aplicaciones Avanzadas
Una lista de reglas solo se mantiene útil si un equipo trata las desviaciones como algo que documentar, no como algo que ocultar.
Decisiones de Arquitectura de Python es el hogar natural para esa documentación: una excepción genuina a una regla ("usamos una caché global mutable aquí porque X") pertenece a un registro de decisiones escrito, no a un comentario silencioso o a un diff sin explicación, porque el próximo ingeniero que lea ese código necesita saber que la excepción fue deliberada.
Esto importa más a medida que una lista crece: una lista de 50 elementos adoptada de una vez, con cada regla de ruff habilitada el primer día, tiende a producir fatiga de alertas: los revisores comienzan a ignorar las advertencias por completo porque demasiadas se activaron a la vez, lo que anula el propósito de automatizar cualquiera de ellas. Adoptar incrementalmente, grupo por grupo, mantiene cada nueva verificación automatizada significativa en lugar de ruido.
El otro eje que vale la pena ser deliberado es el alcance: un script interno único relaja razonablemente las reglas estructurales (organización de módulos, inyección de dependencias) que una biblioteca compartida no puede, mientras que las reglas de seguridad (consultas parametrizadas, manejo de secretos) y las reglas de estilo central se aplican en todas partes, independientemente de cuán desechable parezca el código; "es solo un script" no es una defensa contra una inyección SQL.
| Tipo de lista | Aplicación | Audiencia típica | Riesgo si se usa mal |
|---|---|---|---|
| Lista maestra (general) | Mixta: algunas ruff/mypy, algunas de revisión | Todos los ingenieros, incorporación | Aplicada demasiado rígidamente a código donde el alcance no encaja (scripts, prototipos) |
| Banco de dominio (async/seguridad/datos-ML) | Mayormente revisión + herramientas específicas del dominio (bandit, pip-audit) | Ingenieros que trabajan en ese dominio | Tratado como opcional porque es "especializado", perdido en código inter-dominio |
| Referencia de estilo/PEP 8 | Casi completamente aplicable a través de ruff format | Todos los contribuyentes, a través de puerta de CI | Debates de estilo manuales en revisión a pesar de que una herramienta ya lo decidió |
| Referencia de problema/solución | No es una lista de reglas en absoluto: búsqueda de modismos | Ingenieros que no están seguros del enfoque idiomático | Confundido con una lista de reglas; documenta "cómo", no "debe" |
| Decisiones de arquitectura | No aplicable: un registro de decisiones de juicio tomadas | Revisores que evalúan excepciones a otras reglas | Tratado como documentación opcional en lugar de la fuente de verdad para "por qué nos desviamos" |
Leer bien una lista de reglas significa reconocer en qué fila cae una página dada antes de aplicarla: la Referencia de estilo y PEP 8 y la Referencia de problema / solución no son bancos de reglas prescriptivos en el mismo sentido que las listas numeradas; son material de referencia al que las listas numeradas asumen que puedes consultar cuando una regla hace referencia a una convención o un modismo por nombre.
Conceptos erróneos comunes
- "Una lista de reglas es una especificación completa de código correcto." Es un conjunto codificado de valores predeterminados que reflejan los modos de fallo que el equipo ya conoce; los nuevos modos de fallo - un punto débil de una nueva biblioteca, un nuevo patrón de ataque - no aparecerán en una lista escrita antes de que nadie los haya encontrado.
- "Cada regla de la lista debe ser aplicada por CI." Solo las que son mecánicamente verificables pueden serlo; forzar una regla de decisión de juicio ("separar la lógica de dominio de las E/S") en una puerta automatizada produce falsos positivos o requiere que un linter entienda la intención, lo cual ninguno hace actualmente.
- "La numeración (1-50, 1-30) refleja la prioridad." Refleja la agrupación para la navegación: la regla 45 no es menos importante que la regla 5 porque un grupo posterior aparece más tarde en el documento.
- "Un banco específico del dominio es opcional si ya conoces las reglas generales." Los modos de fallo específicos del dominio (trampas de llamadas bloqueantes de asyncio, fuga de datos de ML) son en gran medida invisibles desde el conocimiento general de Python; la lista general no fue diseñada para detectarlos y no intenta hacerlo.
- "Desviarse de una regla significa que la regla era incorrecta." Una excepción documentada y deliberada para un contexto específico es un uso normal y saludable de una lista de reglas; el modo de fallo es una excepción no documentada que un futuro lector no tiene forma de distinguir de un error.
Preguntas frecuentes
¿Cuál es la diferencia entre una regla y una ley en este contexto?
Una regla es un valor predeterminado codificado con el que el equipo estuvo de acuerdo para no tener que volver a discutirlo en cada PR, pero puede ser anulada deliberadamente con una razón documentada; una ley implica que no hay excepción legítima, que no es cómo se pretende leer ninguna lista en esta sección.
¿Cómo sé si una regla se puede automatizar?
Pregúntate si una herramienta podría verificarla puramente a partir de la sintaxis o los tipos sin entender la intención del código: "no except: genérico" es verificable; "separar la lógica de dominio de las E/S" requiere que un humano juzgue el diseño real, por lo que sigue siendo una regla de tiempo de revisión.
¿Por qué esta sección tiene una lista de 50 elementos Y listas separadas de 30 elementos para async, seguridad y datos/ML?
Porque cada uno de esos dominios tiene modos de fallo invisibles desde el conocimiento general de Python: puntos débiles específicos de asyncio, un modelo de amenaza de seguridad, riesgos específicos de reproducibilidad y fuga de ML, que inflarían una lista general más allá de la utilidad o se diluirían si se fusionaran en ella.
¿La numeración dentro de una lista (como 1-10, 11-20) significa algo más allá de la navegación?
Agrupa reglas relacionadas por dominio (estilo, tipos, estructura, pruebas, seguridad) para que un lector pueda saltar rápidamente a la sección relevante; no es una clasificación de importancia, y los grupos posteriores no tienen menor prioridad que los anteriores.
¿Debería un script interno único seguir todas las reglas de la lista maestra?
Las reglas estructurales (diseño de módulos, inyección de dependencias, diseño de src) se relajan razonablemente para un script desechable, pero las reglas de seguridad y corrección central (consultas parametrizadas, manejo de secretos, validación de entrada) aún se aplican independientemente de cuán pequeño sea el script.
¿Qué debería suceder cuando un equipo decide romper una regla a propósito?
La excepción debe documentarse, típicamente en un registro de decisiones de arquitectura, explicando la razón específica; una excepción no documentada es indistinguible de un descuido para el próximo ingeniero que lea ese código.
¿Por qué no habilitar todas las reglas de ruff/mypy desde el primer día para máxima cobertura?
Habilitar todo a la vez tiende a producir más advertencias de las que un equipo puede actuar significativamente, y los revisores comienzan a ignorar el ruido por completo; adoptar grupos de reglas incrementalmente hace que cada nueva verificación automatizada sea algo a lo que la gente realmente responde.
¿Es la página de Referencia de estilo y PEP 8 también una lista de reglas?
Es material de referencia al que apuntan las reglas numeradas; documenta las convenciones en detalle en lugar de afirmar nuevas reglas de "debe hacer" por sí misma, lo cual es un rol diferente al de los bancos numerados.
¿Cómo se relaciona la página de Referencia de problema/solución con las listas de reglas?
Es una búsqueda de modismos: "cómo hacer X de manera idiomática en Python", no una lista de reglas prescriptiva; responde a una pregunta de "cómo" en la que las listas de reglas no gastan espacio, ya que una regla como "usar pathlib.Path" asume que ya sabes aproximadamente cómo usarla.
¿Para quién está destinada la lista maestra frente a un banco específico del dominio?
La lista maestra está dirigida a todos los ingenieros independientemente de lo que estén construyendo, típicamente utilizada en la incorporación y revisión general de código; un banco de dominio se dirige a ingenieros que trabajan activamente en ese dominio: servicios asíncronos, código sensible a la seguridad o canalizaciones de ML, donde la cobertura de la lista general se agota.
¿Cuál es el riesgo real de tratar una lista de reglas como completa y final?
Crea una falsa confianza en que seguir la lista garantiza la corrección, cuando la lista solo refleja los modos de fallo que el equipo ya conocía en el momento en que se escribió; las nuevas herramientas, las nuevas bibliotecas y los nuevos patrones de ataque no estarán en ella hasta que alguien la actualice.
¿Con qué frecuencia se debe revisar realmente una lista de reglas?
Cada vez que el lenguaje, el framework o las herramientas tienen una versión importante, o después de que un incidente real revela un modo de fallo que la lista no cubrió; una lista estática se vuelve obsoleta silenciosamente de la misma manera que cualquier otra documentación si nada impulsa una revisión.
Relacionados
- 50 reglas de Python que todo especialista debe seguir - la lista maestra general sobre la que se asienta esta página
- 30 reglas asíncronas - modos de fallo específicos de asyncio del dominio
- 30 reglas de seguridad para Python - modelo de amenaza específico del dominio
- 40 reglas de diseño de API (FastAPI/Django/Flask) - reglas de contrato a nivel de framework
- Decisiones de Arquitectura de Python - dónde pertenecen las excepciones documentadas a las reglas
- Referencia de estilo y PEP 8 - el material de referencia al que apuntan las reglas de estilo
Versiones de Stack: Esta página es conceptual y no está vinculada a una versión específica de stack.