{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p>\n",
    "<font size='5' face='Georgia, Arial'>IIC-2233 Apunte Programación Avanzada</font><br>\n",
    "<font size='1'> Material creado en 2019-2 por Equipo Docente IIC2233. Modificado al 2026-1 por Equipo Docente IIC2233</font>\n",
    "</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tabla de contenidos\n",
    "\n",
    "1. [¿Qué es una guía de estilo en programación?](#¿Qué-es-una-guía-de-estilo-en-programación?)\n",
    "2. [¿Por qué usar una guía de estilo?](#¿Por-qué-usar-una-guía-de-estilo?)\n",
    "3. [Guía de estilo en Python: PEP8](#Guía-de-estilo-en-Python:-PEP8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ¿Qué es una guía de estilo en programación?\n",
    "\n",
    "Una guía de estilo es un conjunto de reglas de escritura de código que un programador, o un equipo de ellos, sigue para escribir el código de un programa. Esto asegura que todo archivo escrito siga el mismo formato y parezca provenir de un mismo autor. Estas reglas puede ser variadas: desde **reglas de formato** que deciden si llamar a una variable `mivariable`, `mi_variable` o `miVariable`; hasta **reglas semánticas** que deciden si llamar a una función que suma elementos de una lista `funcion_que_suma` o simplemente `suma`. Qué y cuántas reglas se usan en un proyecto queda completamente definido a gusto de los colaboradores. En general, al trabajar en un equipo grande, se definen en conjunto estas reglas antes de comenzar el proyecto o se usan reglas previamente creadas."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ¿Por qué usar una guía de estilo?\n",
    "\n",
    "A primera vista, el seguir este tipo de reglas puede verse como una restricción o más trabajo a la hora de programar. Sin embargo, el escribir código conscientemente siguiendo una guía de estilo trae muchas ventajas. Específicamente, trae ahorros de tiempo considerables tanto a la hora de escribir código como posterior a su escritura. Es por esto que su uso es una metodología de desarrollo popular en la industria. Distintos equipos de desarrollo, en lugares como Meta, Google, Amazon, Platanus, Fintual y más, utilizan diversas guías de estilo, dependiendo de los proyectos y lenguajes utilizados. \n",
    "\n",
    "A continuación se listan algunas ventajas concretas de usar guías de estilo:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. El código es más leíble\n",
    "\n",
    "El tener reglas de escritura de variables, funciones y clases permite que el código completo sea más fácil de leer. Al programar, uno pasa más tiempo leyendo código que escribiéndolo, por lo que es fundamental contar con código legible que nos permita entender bien o que alguien más entienda lo que ocurre en el programa. Python específicamente, tiene la gracia de una sintaxis muy legible, pero esta propiedad puede perderse rápido con malos hábitos de escritura."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Hace el *debuggeo* más rápido\n",
    "\n",
    "Siguiendo la idea anterior: como programador, uno tiende a quedarse mirando el código por largos periodos de tiempo, sobre todo cuando queremos encontrar un error. A esta actividad de encontrar un problema o un *bug* (🐛) en un programa se le conoce como *debugging*. Si nuestro código es ordenado y leíble, entonces nos puede ahorrar tiempo en encontrar *bugs*."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Se escribe código más rápido\n",
    "\n",
    "A veces, puede tomar tiempo decidir cuál es el nombre más apropiado para cada elemento (variables, funciones y clases). El tener reglas definidas para nombrar objetos nos ayuda a tomar menos decisiones, y por lo tanto, nombrar y escribir más rápido."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Nombres de archivos y variables predecibles\n",
    "\n",
    "En proyectos grandes, lo más seguro es que se usarán múltiples archivos, clases y funciones escritas por ti o por otra persona. Al tener que reutilizar dicho código, es difícil recordar el nombre de cada función, método y clase escrito, lo que provoca perder tiempo buscando dichos nombres manualmente. El tener reglas para escribir y nombrar archivos y variables nos puede ayudar en ahorrar tiempo en esa búsqueda."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Guía de estilo en Python: PEP8\n",
    "\n",
    "PEP8 es la guía de estilo propuesta por la documentación oficial de Python. Esta guía define muchas reglas que siguen los pilares de la filosofía de los creadores de Python. Puedes encontrar la especificación completa [aquí](https://www.python.org/dev/peps/pep-0008/). \n",
    "\n",
    "En IIC2233 utilizaremos solo un subconjunto de reglas de PEP8 para escribir nuestro código (y esperamos que los estudiantes también lo usen en sus tareas). Estas reglas son las siguientes:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Aplicar `snake_case` para nombres de variables, atributos, funciones y métodos.\n",
    "\n",
    "`snake_case` es la práctica de escribir palabras o frases compuestas usando `_` para separar los distintos elementos del nombre y sin espacios. Existen variantes que utilizan mayúsculas para la primera letra, pero en IIC2233 solo usamos minúsculas para este tipo de nombres, y lo usaremos para nombrar **prácticamente todo**, menos los nombres de clases. Esto es: **nombres de variables**, **atributos**, **funciones** y **métodos**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Aplicar `CamelCase` para nombres de clases\n",
    "\n",
    "Por el otro lado, `CamelCase` es la práctica de escribir palabras o frases compuestas sin espacios ni separador entre elementos, y por cada elemento se comienza con una mayúscula. Existen variantes donde la primera letra utilizan minúscula (*lower cammel case*), pero en IIC2233 utilizaremos la opuesta: *upper cammel case*. Este tipo de escritura lo reservamos para el **nombre de clases**."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A continuación, un ejemplo de escritura siguiendo `snake_case` y `CamelCase`:\n",
    "\n",
    "```python\n",
    "class PerroAmigable:\n",
    "    def __init__(self, nombre: str, edad: int) -> None:\n",
    "        self.nombre = nombre\n",
    "        self.edad = edad\n",
    "\n",
    "    def saludar_amigo(self, amigo: PerroAmigable) -> None:\n",
    "        print(\"¡Woof!\")\n",
    "        print(\"¡Hola \" + amigo.nombre + \"!\")\n",
    "\n",
    "\n",
    "def saludo_mutuo(perro_1: PerroAmigable, perro_2: PerroAmigable):\n",
    "    perro_1.saludar_amigo(perro_2)\n",
    "    perro_2.saludar_amigo(perro_1)\n",
    "    print()\n",
    "\n",
    "\n",
    "perro_juan = PerroAmigable(\"Juan\", 21)\n",
    "perro_pedro = PerroAmigable(\"Pedro\", 20)\n",
    "perro_jose = PerroAmigable(\"Jose\", 22)\n",
    "\n",
    "saludo_mutuo(perro_juan, perro_pedro)\n",
    "saludo_mutuo(perro_jose, perro_pedro)\n",
    "saludo_mutuo(perro_juan, perro_jose)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Nombres de variables descriptivos.\n",
    "\n",
    "Es usual que al programar se nos ocurra nombres de variables simples como `a` o `variable`. Si bien tal vez esto ahorra en tiempo de escritura, esto no genera código leíble o fácil de entender. Al volver a leer código como el siguiente, nos produce dudas de que realmente hace lo que estamos leyendo:\n",
    "\n",
    "```python\n",
    "def funcion(l: list) -> int:\n",
    "    i = 0\n",
    "    a = l[0]\n",
    "    for j in range(1, len(l)):\n",
    "        var = l[j]\n",
    "        if var > a:\n",
    "            j = i\n",
    "            a = var\n",
    "    return i\n",
    "```\n",
    "\n",
    "En cambio, al utilizar nombres más descriptivos, queda más claro lo que hace la función:\n",
    "\n",
    "```python\n",
    "def indice_de_maximo(lista: list) -> int:\n",
    "    indice_actual = 0\n",
    "    maximo_actual = lista[0]\n",
    "    for indice in range(1, len(lista)):\n",
    "        elemento = lista[indice]\n",
    "        if elemento > maximo_actual:\n",
    "            indice_actual = indice\n",
    "            maximo_actual = elemento\n",
    "    return indice_actual\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - _Imports_ al comienzo del archivo.\n",
    "\n",
    "Esta convención nos permite ordenar en secciones cada archivo y nos permite encontrar todas las dependencias externas a otras librerías o módulos en un solo lugar, en vez de múltiples secciones:\n",
    "\n",
    "```python\n",
    "import os\n",
    "import random \n",
    "\n",
    "# ...\n",
    "# El resto del código\n",
    "```\n",
    "\n",
    "Más detalles de las sentencias de importación se detallan en el apunte sobre **modularización**."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Un espacio después de la coma (`,`).\n",
    "\n",
    "Para mantener orden, formato y legibilidad, esta regla se aplica en todos los casos que se usan comas al enumerar elementos:\n",
    "\n",
    "```python\n",
    "from random import randint, choice  # Espacios al importar \n",
    "\n",
    "\n",
    "def operaciones_con_potencia(lista: list, potencia: int) -> tuple[int, int]:  # Espacios en definición de funciones\n",
    "    suma = 0\n",
    "    multiplicacion = 1\n",
    "    for elemento in lista:\n",
    "        suma += elemento ** potencia\n",
    "        multiplicacion *= elemento ** potencia\n",
    "    return suma, multiplicacion  # Espacios en retornos\n",
    "\n",
    "\n",
    "numeros = [3, 6, 2, 4]  # Espacios en definición de listas\n",
    "operaciones_con_potencia(numeros, 2)  # Espacios en llamadas de funciones\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Espacios a cada lado de operadores.\n",
    "\n",
    "Para mantener orden, formato y legibilidad, esta regla se aplica siempre que se haga uso de operadores matemáticos:\n",
    "\n",
    "```python\n",
    "valor_1 = ((6 ** 17) - 1) / 2\n",
    "resultado = (1 + valor_1) * 3\n",
    "resto_en_dos = resultado % 2\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - No usar _tabs_. Usar 4 espacios para indentar.\n",
    "\n",
    "Python3 no permite mezclar ambos tipos en un archivo para indentar bloques de código. Se prefiere usar **cuatro espacios** para cada nivel de indentación, no _tabs_. Dependiendo del editor de texto, hay formas de configurar el uso de espacios y _tabs_ al escribir automáticamente. Las tres interfaces de desarrollo recomendadas para el curso permiten esta funcionalidad, puedes encontrar manuales de instalación [aquí](https://github.com/IIC2233/Syllabus/wiki/5.-Interfaces-de-Desarrollo)."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### - Líneas de largo máximo de 100 caracteres (incluyendo espacios e indentación).\n",
    "\n",
    "Es recurrente el problema de líneas muy largas, sobre todo en líneas ya indentadas. Generalmente, se establece el límite de 80 caracteres como máximo para seguir una convención de compatibilidad con herramientas de edición que establecen este límite y permiten ver el código solo de ese ancho de espacio. Pero, en el curso relajaremos esta regla y trabajaremos con líneas de **máximo 100 caracteres**. Hay varias formas de evitar este problema, pero depende del contexto en el que se encuentre el problema. A veces es conveniente aprovechar la creación de variables extras para expresiones largas y acortar líneas, o en casos extremos, el uso de `\\` que permite separar una línea larga en la siguiente.\n",
    "\n",
    "Por ejemplo, el siguiente código tiene líneas que se pueden acortar:\n",
    "\n",
    "```python\n",
    "print(\"Debe ingresar dos números\")\n",
    "valor_1 = int(input(\"Ingrese primer número\"))\n",
    "valor_2 = int(input(\"Ingrese segundo número\"))\n",
    "# La siguiente línea es muy larga\n",
    "if valor_1 + valor_2 >= 1000 and (valor_1 - valor_2 >= 1000 or valor_2 - valor_1 >= 1000):\n",
    "    print(\"Los números suman mucho y están muy separados\")\n",
    "elif valor_1 + valor_2 >= 1000:\n",
    "    print(\"Los números suman mucho\")\n",
    "elif (valor_1 - valor_2 >= 1000 or valor_2 - valor_1 >= 1000):\n",
    "    print(\"Los números están muy separados\")\n",
    "else:\n",
    "    print(\"Los números son apropiados\")\n",
    "```\n",
    "\n",
    "Mediante el uso de `\\`:\n",
    "\n",
    "```python\n",
    "print(\"Debe ingresar dos números\")\n",
    "valor_1 = int(input(\"Ingrese primer número\"))\n",
    "valor_2 = int(input(\"Ingrese segundo número\"))\n",
    "# Se separó usando \\\n",
    "if valor_1 + valor_2 >= 1000 and \\\n",
    "            (valor_1 - valor_2 >= 1000 or valor_2 - valor_1 >= 1000):\n",
    "    print(\"Los números suman mucho y están muy separados\")\n",
    "elif valor_1 + valor_2 >= 1000:\n",
    "    print(\"Los números suman mucho\")\n",
    "elif (valor_1 - valor_2 >= 1000 or valor_2 - valor_1 >= 1000):\n",
    "    print(\"Los números están muy separados\")\n",
    "else:\n",
    "    print(\"Los números son apropiados\")\n",
    "```\n",
    "\n",
    "O el uso de variables auxiliares:\n",
    "\n",
    "```python\n",
    "print(\"Debe ingresar dos números\")\n",
    "valor_1 = int(input(\"Ingrese primer número\"))\n",
    "valor_2 = int(input(\"Ingrese segundo número\"))\n",
    "# Variables auxiliares para mejorar legibilidad\n",
    "suma = valor_1 + valor_2\n",
    "diferencia = abs(valor_1 - valor_2)\n",
    "if suma >= 1000 and diferencia >= 1000:\n",
    "    print(\"Los números suman mucho y están muy separados\")\n",
    "elif suma >= 1000:\n",
    "    print(\"Los números suman mucho\")\n",
    "elif diferencia >= 1000:\n",
    "    print(\"Los números están muy separados\")\n",
    "else:\n",
    "    print(\"Los números son apropiados\")\n",
    "```\n",
    "\n",
    "En general, se prefiere reescribir el código de tal forma de evitar usar `\\`, ya que no es tan legible. También, la intención de esta regla es no escribir líneas largas en general, no solo arreglar aquellas que superen el límite de 100 caracteres."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
