-
Notifications
You must be signed in to change notification settings - Fork 2
LOG
Documentación personal sobre temas relacionados con python: pruebas, trozos de código, experimentos, etc... Es un borrador, y la información está muy desorganizada
Voy a reciclarme en python, para aprender cosas nuevas. Este es uno de los tutoriales que voy a seguir, que es el oficial:
https://docs.python.org/3/tutorial/
Python lo voy a usar para hacer shell scripts en Linux. Los podría hacer directamente en bash, pero prefiro hacerlos en python. Al final, el bash siempre se me acaba olvidando... y me parece muy críptico y poco legible
También lo quiero para continuar con el desarrollo de APIO, que está en python, y para crear diferentes utilidades para usar con la FPGA
Comienzo con la lectura del tutorial de python: https://docs.python.org/3/tutorial/
La biblioteca estándar de python está documentada aquí: https://docs.python.org/3/library/index.html#library-index
No comentan nada nuevo. Sólo hacen énfasis en que una de las aplicaciones estrellas de python es precisamente la de hacer scripts para la shell... que es una de las cosas para las que yo lo quiero
Como estoy trabajando en ubuntu 22.04, el python que hay instalado en el sistema es el 3.10. Se ejecuta con python3:
obijuan@Hoth:~
$ python3
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
El ejecutable está instalado aquí: /usr/bin/python3
$ which python3
/usr/bin/python3
obijuan@Hoth:~
$
Del intérprese se sale con el comando quit():
$ python3
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
obijuan@Hoth:~
Es posible ejecutar directamente comandos de python con el parámetro -c:
obijuan@Hoth:~
$ python3 -c "print('hello')"
hello
obijuan@Hoth:~
Con el parámetro -i se entra en el modo interactivo tras la ejecución del comando/script:
obijuan@Hoth:~
$ python3 -i -c "print('hello')"
hello
>>>
Todo esto funciona, por supuesto, con el ipython3 (mismos parámetros)
Por defecto los ficheros en python se tratan con condificacion UTF-8. Esto nos permite usar los caracteres extendidos en el código, así como emoticonos 🙂️
Los ejemplos que haga relacionados con este tutorial los voy a guardar en la carpeta Examples/Python-tutorial, organizados por capítulo.
Este es el primer ejemplo, del capítulo 2: 01-shebang.py
#!/usr/bin/env python3
print("Hola🙂️")Es un hola mundo pero que incluye en la primera línea el intérprete de python. De esta forma podemos convertir directamente el archivo a ejecutable y lanzarlo desde la consola:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-2
$ ./01-shebang.py
Hola🙂️
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-2
$
Todos los ejemplos los voy a desarrollar con VS-code. Tengo instalada la extensión de python de intellisense (que es la oficial). Para poder depurar y ejecutar los programas hay que crear el fichero launch.json dentro de la carpeta .vscode. Esta es la pinta que tiene:
(Es un fichero JSON con comentarios)
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}Esto hace que por defecto se ejecute el programa usando el terminal intergrado del visual. Al ejecutarlo desde el visual (desde la parte de Run and Debug), se abre el terminal interno y aparece esto:
obijuan@Hoth:~/Develop/Learn-python
$ /usr/bin/env /bin/python3 /home/obijuan/.vscode/extensions/ms-python.python-2023.4.0/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher 45021 -- /home/obijuan/Develop/Learn-python/Examples/Python-tutorial/Capitulo-2/01-shebang.py
Hola🙂️
obijuan@Hoth:~/Develop/Learn-python
$
Si se ejecuta de nuevo se reutiliza el terminal ya abierto (no se abre otro nuevo). También se puede hacer que se ejecute por defecto desde un terminal externo cambiando la propiedad console del fichero launch.json
...
"console": "externalTerminal",
...Algunos tipos básicos con:
-
int: Número entero -
float: Número en coma flotante -
bool: Booleano -
str: Cadenas
La función type devuelve el tipo:
In [11]: type(34)
Out[11]: int
In [12]: type(34.3)
Out[12]: float
In [13]: type(True)
Out[13]: bool
In [14]: type("hola")
Out[14]: strEn las cadenas se usa el carácter \ como escape, por ejemplo para mostrar comillas. Pero también es posible utilizar cadenas crudas (raw) en las que este carácter no se interpreta:
In [1]: print('C:\some\name')
C:\some
ame
In [2]: print(r'C:\some\name')
C:\some\nameCon las 3 comillas """ se meten cadenas de texto incluyendo los saltos de línea
#!/usr/bin/env python3
BOX = """
+----------+
| |
+----------+
"""
print(BOX)
print(BOX)Esto es lo que se muestra al ejecutar:
$ ./01-string-menu.py
+----------+
| |
+----------+
+----------+
| |
+----------+
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
Es posible eliminar los saltos de línea de alguna línea en particular (por ejemplo de la primera y de la última) usando el carácter '' al final de la línea. Esto es muy útil, por ejemplo, para hacer que las dos cajas anteriores aparezcan unidas
#!/usr/bin/env python3
BOX = """\
+----------+
| |
+----------+\
"""
print(BOX)
print(BOX)Ahora obtenemos esto:
$ ./01-string-menu.py
+----------+
| |
+----------+
+----------+
| |
+----------+
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
Aprovecho este ejemplo para crear unas cajas usando caracteres UNICODE de cajas. Y ya puestos, voy a preguntarle esta información al CHatGPT
Pregunta: Dame información sobre los caracteres unicode para dibujar cajas en la consola
Respuesta:
¡Claro! Los caracteres Unicode que puedes utilizar para dibujar cajas en la consola dependen del conjunto de caracteres que soporta tu terminal. Sin embargo, aquí te proporcionaré algunos de los caracteres Unicode más comunes que se utilizan para dibujar cajas:
Caracteres de esquina:
┌ U+250C : BOX DRAWINGS LIGHT DOWN AND RIGHT
┐ U+2510 : BOX DRAWINGS LIGHT DOWN AND LEFT
└ U+2514 : BOX DRAWINGS LIGHT UP AND RIGHT
┘ U+2518 : BOX DRAWINGS LIGHT UP AND LEFT
Caracteres de línea:
─ U+2500 : BOX DRAWINGS LIGHT HORIZONTAL
│ U+2502 : BOX DRAWINGS LIGHT VERTICAL
Caracteres de intersección:
├ U+251C : BOX DRAWINGS LIGHT VERTICAL AND RIGHT
┤ U+2524 : BOX DRAWINGS LIGHT VERTICAL AND LEFT
┬ U+252C : BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
┴ U+2534 : BOX DRAWINGS LIGHT UP AND HORIZONTAL
┼ U+253C : BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
Ten en cuenta que la apariencia de estos caracteres puede variar según la fuente y el terminal que estés utilizando. Además, hay muchos otros caracteres Unicode que se pueden utilizar para dibujar cajas y otros símbolos gráficos.
Este es el ejemplo para imprimir la caja:
#!/usr/bin/env python3
print("┌─────────┐")
print("│ │")
print("└─────────┘")
Al ejecutarlo se obtiene esto:
$ ./02-box-unicode.py
┌─────────┐
│ │
└─────────┘
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
En el terminal la caja se ve sin cortes:

En python podemos colocar dos cadenas (literales) independientes, una a continuación de la otra. El intérprete nos las concatenará
In [1]: "hola" "mundo"
Out[1]: 'holamundo'
Esto es muy útil para separar líneas largas en otras más cortas, y para mejorar la legibilidad de los programas en general
#!/usr/bin/env python3
#-- Estos mensajes se imprimen en la misma línea
print("-Mensaje 1-"
"-Mensaje 2-")Y este es el resultado de la ejecución:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$ ./03-string-test.py
-Mensaje 1--Mensaje 2-
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
Sólo funciona con cadenas literales. Si queremos concatenar dos cadenas definidas en variables se utiliza el operandor +
In [5]: hola="hola"
In [6]: mundo=" mundo"
In [7]: print(hola + mundo)
hola mundo
In [8]:
El operador de multiplicación * aplicado a cadenas nos permite repetirlas el número de veces indicado. Así, la operación 3 * 'A' genera la siguiente cadena: "AAA"
In [9]: print(3 * 'A')
AAA
Este operador es ¡extremadamente útil!. Con el podemos generar líneas horizontales muy fácilmente, de cualquier longitud
#!/usr/bin/env python3
#-- Anchura de la linea
width = 20
#-- Dibujar linea de la anchura indicada
print("─" * width)Este es el resultado
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$ ./04-string-linea.py
────────────────────
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
En este ejemplo se se imprime un mensaje entre dos líneas, y este mensaje se indenta usando el operandor * también:
#!/usr/bin/env python3
#-- Anchura de la linea
width = 20
MESSAGE = "MENU"
INDENT = 3
#-- Dibujar linea de la anchura indicada
print("─" * width)
#-- Imprimir el mensaje con indentado
print (" " * INDENT + MESSAGE)
#-- Dibujar linea inferior
print("─" * width)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$ ./05-string-mensaje-lineas.py
────────────────────
MENU
────────────────────
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
Para el acceso a los caracteres individuales de la cadena se pueden usar índices positivos o negativos. Cuando se usan negativos, -1 se corresponde con el último carácter:
In [20]: cad="012345"
In [21]: cad[0]
Out[21]: '0'
In [22]: cad[5]
Out[22]: '5'
In [23]: cad[-1]
Out[23]: '5'
In [24]: cad[-2]
Out[24]: '4'También se pueden obtener fragmentos contiguos de caracteres (slices), indicando el índice inicial y el final (pero el final no se incluye). Si no se indica el inicial, se parte desde 0. Si no se indica el final, se parte toma el último
In [1]: cad="012345"
In [2]: cad[0:2]
Out[2]: '01'
In [3]: cad[1:3]
Out[3]: '12'
In [4]: cad[:3]
Out[4]: '012'
In [5]: cad[-2:]
Out[5]: '45'
In [6]:El carácter correspondiente al índice final no se incluye en el slice para que se pueden hacer operacioens como estas:
In [13]: cad="012345"
In [14]: i=3
In [15]: cad[:i] + cad[i:]
Out[15]: '012345'
In [16]: cad[:i] + "|" + cad[i:]
Out[16]: '012|345'
In [17]:Es decir, que la cadena cad[:i] + cad[i:] sea siempre igual a la original
IMPORTANTE: El uso del operador [a:b] NO GENERA UNA EXCEPCION si los índices están fuera de rango. Simplemente devolverá bien la cadena vacía o los caracteres contenidos en ese fragmento
In [21]: cad="012345"
In [22]: cad[4:10]
Out[22]: '45'
In [23]: cad[6:10]
Out[23]: ''
In [24]: IMPORTANTE: Las cadenas en python son inmutables (no se pueden modificar sus caracteres de manera aislada)
In [26]: cad="012345"
In [27]: cad[0]='A'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-27-c266e78be102> in <module>
----> 1 cad[0]='A'
TypeError: 'str' object does not support item assignment
In [28]: Por ello, si para obtener una cadena modificada hay que generar una cadena nueva que copie los caracteres de la cadena origina
la función len nos devuelve la longitud de la cadena (en número de caracteres)
In [29]: cad="012345"
In [30]: len(cad)
Out[30]: 6En estos enlaces se puede encontrar más información sobre las cadenas:
Strings are examples of sequence types, and support the common operations supported by such types.
Strings support a large number of methods for basic transformations and searching.
String literals that have embedded expressions
Para imprimir colores en las consolas de texto utilizamos los códigos ANSI. Vamos a preguntarle a ChatGPG:
- PREGUNTA:
Muéstrame los códigos ANSI para cambiar el color de los caracteres en la consola
- RESPUESTA:
Los códigos ANSI para cambiar el color de los caracteres en la consola dependen del sistema operativo y del lenguaje de programación que se esté utilizando. A continuación se muestran algunos ejemplos de códigos ANSI para cambiar el color de los caracteres en la consola utilizando Python en un sistema operativo Unix/Linux:
# Código ANSI para cambiar el color del texto a rojo
print('\033[91m' + 'Texto rojo' + '\033[0m')
# Código ANSI para cambiar el color del fondo a amarillo
print('\033[43m' + 'Texto con fondo amarillo' + '\033[0m')
# Código ANSI para cambiar el color del texto a verde y el fondo a azul
print('\033[32;44m' + 'Texto verde con fondo azul' + '\033[0m')En estos ejemplos, \033 es el código de escape ANSI, seguido de uno o varios códigos numéricos separados por punto y coma. El código \033[0m se utiliza al final para volver al color predeterminado de la consola.
Es importante tener en cuenta que no todos los sistemas operativos y terminales de consola admiten los códigos ANSI de la misma manera, por lo que es posible que estos ejemplos no funcionen en todos los casos.
Este es un ejemplo hola mundo para imprimir un mensaje en rojo:
#!/usr/bin/env python3
#-- Definiciones ANSI para los colores
RED = "\x1B[91m"
#------ Otros caracteres especiales
#-- Volver al color por defecto
DEFAULT = "\x1B[0m"
#-- Imprimir mensaje en Rojo
print(RED + "Mensaje en color rojo" + DEFAULT)
#-- Imprimir mensaje normal
print("Este es un mensaje normal...")Y esto es lo que aparece al ejecutarse:

Le preguntamos a ChatGPT por un listado de los colores del fondo:
- PREGUNTA:
Dame un listado de todos los códigos ANSI para el color del texto (pero no del fondo)
- RESPUESTA:
A continuación se muestra un listado de todos los códigos ANSI para cambiar el color del texto en la consola:
\033[30m: texto negro
\033[31m: texto rojo
\033[32m: texto verde
\033[33m: texto amarillo
\033[34m: texto azul
\033[35m: texto magenta
\033[36m: texto cian
\033[37m: texto blanco
Cada uno de estos códigos se utiliza para establecer el color del texto correspondiente. Por ejemplo, si se desea cambiar el color del texto a azul, se puede utilizar el código \033[34m. Es importante tener en cuenta que, al igual que en el ejemplo anterior, se debe utilizar el código \033[0m al final para volver al color predeterminado de la consola.
En este ejemplo probamos todos estos los colores:
#!/usr/bin/env python3
#-- Definiciones ANSI para los colores
NEGRO = "\x1B[30m"
RED = "\x1B[31m"
GREEN = "\x1B[32m"
YELLOW = "\x1B[33m"
BLUE = "\x1B[34m"
MAGENTA = "\x1B[35m"
CYAN = "\x1B[36m"
WHITE = "\x1B[37m"
#------ Otros caracteres especiales
#-- Volver al color por defecto
DEFAULT = "\x1B[0m"
#-- Imprimir mensajes en diferentes colores
print(NEGRO + "Mensaje en negro")
print(RED + "Mensaje en color rojo")
print(GREEN + "Mensaje en color verde")
print(YELLOW + "Mensaje en color amarillo")
print(BLUE + "Mensaje en azul")
print(MAGENTA + "Mensaje en magenta")
print(CYAN + "Mensaje en Cyan")
print(WHITE + "Mensaje en blanco")
#-- Imprimir mensaje normal
print(DEFAULT + "Este es un mensaje normal...")Y esto es lo que obtenemos:

Vamos a preguntar a ChatGPT por los códigos de los colores más brillantes:
- PREGUNTA
Muéstrame más códigos ANSI para el color del texto, pero que sean más brillantes
- RESPUESTA
Claro, a continuación se muestran los códigos ANSI para los colores del texto más brillantes, disponibles en algunos terminales:
\033[90m: texto gris claro
\033[91m: texto rojo claro
\033[92m: texto verde claro
\033[93m: texto amarillo claro
\033[94m: texto azul claro
\033[95m: texto magenta claro
\033[96m: texto cian claro
\033[97m: texto blanco brillante
Al igual que los códigos ANSI anteriores, estos códigos se utilizan para establecer el color del texto correspondiente. Es importante tener en cuenta que estos códigos solo funcionarán si el terminal y el sistema operativo lo soportan. Además, no todos los terminales y sistemas operativos pueden mostrar estos colores de manera brillante o pueden mostrarlos de manera diferente.
Y lo probamos con este programa de ejemplo:
#!/usr/bin/env python3
#───────────────────────────────────────
# Definiciones ANSI para los colores
#───────────────────────────────────────
#── Colores normales
GREY = "\x1B[30m"
RED = "\x1B[31m"
GREEN = "\x1B[32m"
YELLOW = "\x1B[33m"
BLUE = "\x1B[34m"
MAGENTA = "\x1B[35m"
CYAN = "\x1B[36m"
WHITE = "\x1B[37m"
#── Colores brillantes
LGRAY = "\x1B[90m"
LRED = "\x1B[91m"
LGREEN = "\x1B[92m"
LYELLOW = "\x1B[93m"
LBLUE = "\x1B[94m"
LMAGENTA = "\x1B[95m"
LCYAN = "\x1B[96m"
LWHITE = "\x1B[97m"
#──── Otros caracteres especiales
#── Volver al color por defecto
DEFAULT = "\x1B[0m"
#── Imprimir mensajes en diferentes colores
print(GREY + "Mensaje en Gris")
print(LGRAY + "Mensaje en gris claro")
print(RED + "Mensaje en color rojo")
print(LRED + "Mensaje en Rojo claro")
print(GREEN + "Mensaje en color verde")
print(LGREEN + "Mensaje en color verde claro")
print(YELLOW + "Mensaje en color amarillo")
print(LYELLOW + "Mensaje en color amarillo claro")
print(BLUE + "Mensaje en azul")
print(LBLUE + "Mensaje en azul claro")
print(MAGENTA + "Mensaje en magenta")
print(LMAGENTA + "Mensaje en magenta claro")
print(CYAN + "Mensaje en Cyan")
print(LCYAN + "Mensaje en Cyan claro")
print(WHITE + "Mensaje en blanco")
print(LWHITE + "Mensaje en blanco claro")
#── Imprimir mensaje normal
print(DEFAULT + "Este es un mensaje normal...")Este es el resultado:

Algunos colores son iguales, como por ejemplo el gris (normal y claro) o el blanco
Seguimos a partir de aquí:
https://docs.python.org/3/tutorial/introduction.html#lists
Las listas son un tipo de secuencias. Se le pueden aplicar los operadores de las cadenas (que también son secuencias), como los fragmentos
In [1]: l = [0,1,2,3,4,5,6]
In [2]: l[-1]
Out[2]: 6
In [3]: l[0]
Out[3]: 0
In [4]: l[0:2]
Out[4]: [0, 1]Cuando se aplica [] para obtener fragmentos, estos fragmetnos son copias. Por ello, si queremos realizar una copia de una lista, usamos [:]
In [1]: l1 = [0,2,3,4,5,6]
In [2]: l2 = l1
In [3]: l1, l2
Out[3]: ([0, 2, 3, 4, 5, 6], [0, 2, 3, 4, 5, 6])
In [4]: l2[0]='a'
In [5]: l1, l2
Out[5]: (['a', 2, 3, 4, 5, 6], ['a', 2, 3, 4, 5, 6])
In [6]: l3 = l1[:]
In [7]: l1,l2,l3
Out[7]: (['a', 2, 3, 4, 5, 6], ['a', 2, 3, 4, 5, 6], ['a', 2, 3, 4, 5, 6])
In [8]: l3[0]='f'
In [9]: l1,l2,l3
Out[9]: (['a', 2, 3, 4, 5, 6], ['a', 2, 3, 4, 5, 6], ['f', 2, 3, 4, 5, 6])Operación de contenación con +:
In [1]: l = [0,1] + [2,3,4]
In [2]: l
Out[2]: [0, 1, 2, 3, 4]
Las listas son mutables (a diferencia de las cadenas). Se pueden cambiar sus elementos. Y además se pueden cambiar usando fragmentos:
In [1]: l = ['a', 'b', 'c', 'd']
In [2]: l[1:3]=['B', 'C']
In [3]: l
Out[3]: ['a', 'B', 'C', 'd']
In [4]: l[1:3]=[]
In [5]: l
Out[5]: ['a', 'd']La función len() también se usa
In [1]: l = ['a', 'b', 'c', 'd']
In [2]: len(l)
Out[2]: 4Este es el ejemplo para calcular fibonacci:
#!/usr/bin/env python3
a, b = 0, 1
while a < 10:
print(a)
a, b = b, a+bEl resultado de la ejecución es este:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$ ./06-fibonacci.py
0
1
1
2
3
5
8
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
Para hacer que los números salgan en horizontal, utilizando como separador por ejemplo una coma ,, usamos el parámetro end de la función print()
#!/usr/bin/env python3
a, b = 0, 1
while a < 10:
print(a, end=",")
a, b = b, a+b
print()Y esta es la nueva salida:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$ ./07-fibonacci-2.py
0,1,1,2,3,5,8,
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-03
$
La función input() devuelve la cadena introducida por el usuario
#!/usr/bin/env python3
cad = input("Introduzca una cadena: ")
print("Has escrito: " + cad)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./01-input-string.py
Introduzca una cadena: hola
Has escrito: hola
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$
Para leer números convertimos la cadena devuelva por input() a entero, usando int()
#!/usr/bin/env python3
num = int(input("Introduzca un número: "))
print("El número es: " + str(num))Lo probamos:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./02-input-int.py
Introduzca un número: 73
El número es: 73
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$
#!/usr/bin/env python3
num = int(input("Introduce un número: "))
if num < 0:
print("Número negativo")
elif num == 0:
print("Es 0")
else:
print("Número positivo")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./03-input-num.py
Introduce un número: -5
Número negativo
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$#!/usr/bin/env python3
words = ["hola", "probando", "1234567890"]
for w in words:
print(w, len(w))Resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./04-for-1.py
hola 4
probando 8
1234567890 10
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$Cuando se modifica una colección a la vez que se está modificando suele dar problemas. Por eso es mejor iterar sobre una copia de la colección (o crear una nueva):
#!/usr/bin/env python3
#-- Crear una coleccion simple
users = {
"Obijuan": "activo",
"Dark vader": "inactivo",
"Yoda": "activo",
"luke skywalker": "inactivo"
}
#-- Eliminar los usuarios inactivos
#-- Estrategia 1: Iterar sobre una copia,
#-- borrar de la colección original
#-- users.copy() es una copia
for user, estado in users.copy().items():
if estado == "inactivo":
del users[user]
print(users)
#-- Estrategia 2: Crear una lista nueva
user_activos = {}
for user, estado in users.items():
if estado == "activo":
user_activos[user] = estado
print(user_activos)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./05-for-copy.py
{'Obijuan': 'activo', 'Yoda': 'activo'}
{'Obijuan': 'activo', 'Yoda': 'activo'}
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ Esta función nos permite iterar por números enteros
#!/usr/bin/env python3
for i in range(10):
print(i)Resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./06-range.py
0
1
2
3
4
5
6
7
8
9
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$En la función range() también se puede indicar el comienzo, el fin y el incremento:
In [1]: list(range(5,10))
Out[1]: [5, 6, 7, 8, 9]
In [2]: list(range(0,10,3))
Out[2]: [0, 3, 6, 9]
In [3]: list(range(-10,-100,-30))
Out[3]: [-10, -40, -70]Para iterar por los índices se puede hacer así:
#!/usr/bin/env python3
a = ["Obijuan", "Darth Vader", "Yoda", "Han Solo"]
#-- Recorrer la lista usando los índices
for i in range(len(a)):
print(i, a[i])Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./07-range2.py
0 Obijuan
1 Darth Vader
2 Yoda
3 Han Solo
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$La función sum() toma como argumeto un iterable y realiza la suma
In [1]: sum(range(4))
Out[1]: 6El break sale del bucle. Si no se ejecuta ningún break se ejecuta lo que hay en el else tras el for. Este ejemplo calcula la divisibilidad. Si termina el bucle interior sin break, significa que no hay divisor, por lo que es primero (se ejecuta lo que hay en el else)
#!/usr/bin/env python3
#-- Calcular la divisibilidad de los numeros entre 2 y 10
for n in range(2, 10):
#-- Dividir n entro todos los numeros inferiores a n
for x in range(2, n):
#-- Numero divisible
if n % x == 0:
print(n, 'equals', x, '*', n//x)
break
#-- No es divisible
else:
# loop fell through without finding a factor
print(n, 'is a prime number')Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./08-break-else.py
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$Con continue se evalúa la siguiente iteración
#!/usr/bin/env python3
#-- Catalogar los números del 2 al 10
#-- entre pares e impares
for n in range(2,10):
#-- Divisible entre 2: par
if n % 2 == 0:
print(n, "es par")
#-- Pasar a la siguiente iteración
continue
#-- Es impar
print(n, "es Impar")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./09-continue.py
2 es par
3 es Impar
4 es par
5 es Impar
6 es par
7 es Impar
8 es par
9 es Impar
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$Esperar a que se apriete Ctrl-C:
#!/usr/bin/env python3
#-- Esperar hasta que se apriete Ctrl-C
while True:
passEl match es similar al case, pero un poco más avanzado
#!/usr/bin/env python3
print("1.- Opcion 1")
print("2.- Opcion 2")
print("3.- Terminar")
while True:
op = int(input("Elige opcion: "))
match(op):
case 1:
print("Opción 1")
case 2:
print("Opción 2")
case 3:
print("Terminar")
break
case _:
print("Opción inválida")Este es el resultado al ejecutar:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./11-match.py
1.- Opcion 1
2.- Opcion 2
3.- Terminar
Elige opcion: 1
Opción 1
Elige opcion: 2
Opción 2
Elige opcion: 5
Opción inválida
Elige opcion: 2
Opción 2
Elige opcion: 3
Terminar
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ Ejemplo de uso de patrones con variables:
#!/usr/bin/env python3
#- Lista de puntos cartesianos
puntos = [(0,0), (0,3), (5,0), (7,9), (-3,5)]
#-- Recorrer todos los puntos
for p in puntos:
#-- Imprimr el tipo de punto
match(p):
case (0,0):
print("* Origen")
case (0,x):
print("* Sobre eje X")
case (y,0):
print("* Sobre eje Y")
case (x,y):
print("* Punto (",x,y,")")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./12-match-02.py
* Origen
* Sobre eje X
* Sobre eje Y
* Punto ( 7 9 )
* Punto ( -3 5 )
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$En la definición de las funciones se pueden establecer opcionalmente el tipo de parámetro, para que sea más fácil detectar errores
#!/usr/bin/env python3
#-- Imprimir los numeros de fibonacci hasta el número n
def fibo(n: int):
a,b = 0,1
while b < n:
print(b, end=" ")
a,b = b, a+b
#-- Llamar a la funcion
fibo(100)Este es el resultao de la ejecución:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./13-func-fibonacci.py
1 1 2 3 5 8 13 21 34 55 89
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$Las funciones deuelve valores con return:
#!/usr/bin/env python3
#-- Imprimir los numeros de fibonacci hasta el número n
def fibo(n: int) -> list:
"""Lista con los numeros de fibonacci hasta el numero n"""
a,b = 0,1
#- Lista donde almacenar la lista de fibonacci
result = []
while b < n:
#-- Añadir elemento a la lista
result.append(b)
#-- Actualizar termino de fibonacci
a,b = b, a+b
#-- Devolver la lista
return result
#-- Llamar a la funcion
l=fibo(100)
print("Lista de fibonacci: ", l)Esta es la ejecución:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./14-func-fibonacci-2.py
Lista de fibonacci: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ Las funciones pueden tener un número variable de argumentos. Esto se puede hacer de tres formas. La primera es usando parámetros por defecto
#!/usr/bin/env python3
def ask_ok(prompt : str, retries=4, remainder="Please, try again") -> bool:
"""Esperar respuesta de confirmación"""
while True:
ok = input(prompt)
if ok in ('s', 'si'):
return True
if ok in ('n', 'no', 'nope'):
return False
retries = retries - 1;
if retries < 0:
raise ValueError('Respuesta inválida')
print(remainder)
#-- Mensaje al usuario
while True:
if ask_ok("Quiere terminar?"):
breakLa función ask_ok() se puede invocar de muchas maneras. El primer parámetro es obligatorio: el mensaje a imprimir. El resto de parámetros son opcioneles y se pueden establecer al llamar a la función:
ask_ok("fin?", retries=1)A las funciones se le pueden pasar múltiples argumentos, agrupados en una tupla... Pero para no tener que escribir la tupla, se usa el operandor * para desempaquetar la tupla. Así, si tenemos esta tupla: (1,2,3), Al aplicar el operador * se convierte en 1,2,3
En este ejemplo se ha definido la función debug() que acepta un número variable de parámetros. Esto se indica en la definición con el parámetro formal *args
#!/usr/bin/env python3
#-- Funcion con parámetros variables (ninguno, uno, dos....)
def debug(*args):
print("LLamada")
print(" Tupla: ", args)
print(" Argumentos pasados: ", len(args))
#-- Imprimri todos los argumetnos pasados
print(" ", end='')
for arg in args:
print(arg, end=' ')
print()
#-- Llamar a la función con diferentes parámetros
debug()
debug(1)
debug(1,"hola")
debug(1,2,3,4)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./16-func-list.py
LLamada
Tupla: ()
Argumentos pasados: 0
LLamada
Tupla: (1,)
Argumentos pasados: 1
1
LLamada
Tupla: (1, 'hola')
Argumentos pasados: 2
1 hola
LLamada
Tupla: (1, 2, 3, 4)
Argumentos pasados: 4
1 2 3 4
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ Este operador * es muy interensate. Nos permite pasar los elementos de una lista como argumetnos a una función. Lo vamos a probar llamando a print:
In [1]: l = list(range(10))
In [2]: l
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [4]: print(*l)
0 1 2 3 4 5 6 7 8 9
In [5]: print(0,1,2,3,4,5,6,7,8,9)
0 1 2 3 4 5 6 7 8 9
In [6]: Lo mismo se puede hacer con los diccionarios, pasando argumentos de la forma "nombre = valor":
#!/usr/bin/env python3
#-- Funcion con parámetros clave pasados a través de un diccionario
def debug(**args):
print("LLamada")
print(" Diccionario: ", args)
print(" Argumentos pasados: ", len(args))
# #-- Imprimir todos los argumetnos pasados
for arg in args:
print(" ", arg, "---> ", args[arg])
print()
#-- Llamar a la función con diferentes parámetros
debug()
debug(a1=1, a2=2)
debug(a=1, b="hola", c="vamos")Esto es lo que se obtiene al probar:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ ./17-func-dict.py
LLamada
Diccionario: {}
Argumentos pasados: 0
LLamada
Diccionario: {'a1': 1, 'a2': 2}
Argumentos pasados: 2
a1 ---> 1
a2 ---> 2
LLamada
Diccionario: {'a': 1, 'b': 'hola', 'c': 'vamos'}
Argumentos pasados: 3
a ---> 1
b ---> hola
c ---> vamos
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-04
$ Las listas las podemos usar fácilmente para implementar pilas. El método append añade un elemento al final. Es equivalente a un push. El método pop devuelve el último elemento de la lista
In [1]: #-- Crear pila
In [2]: pila = []
In [3]: #-- Push(1)
In [4]: pila.append(1)
In [5]: pila
Out[5]: [1]
In [6]: #-- Push(2)
In [7]: pila.append(2)
In [8]: #-- Push(3)
In [9]: pila.append(3)
In [10]: pila
Out[10]: [1, 2, 3]
In [11]: pila.pop()
Out[11]: 3
In [12]: pila
Out[12]: [1, 2]
In [13]: pila.pop()
Out[13]: 2
In [14]: pila.pop()
Out[14]: 1
In [15]: pila
Out[15]: []
In [16]: Para implementar Colas es mejor utilizar el objeto collections.deque
Se usa el método append para añadir a la cola y popleft() para leer de la cola
In [1]: from collections import deque
In [2]: cola = deque([])
In [3]: cola
Out[3]: deque([])
In [4]: cola.append("uno")
In [5]: cola.append("dos")
In [6]: cola
Out[6]: deque(['uno', 'dos'])
In [7]: cola.append("tres")
In [8]: cola
Out[8]: deque(['uno', 'dos', 'tres'])
In [9]: cola.popleft()
Out[9]: 'uno'
In [10]: cola.popleft()
Out[10]: 'dos'
In [11]: cola.popleft()
Out[11]: 'tres'
In [12]: cola
Out[12]: deque([])
In [13]: Los diccionarios se usan mucho... Se puede iterar sobre ellos de diferentes formas:
#!/usr/bin/env python3
#-- Crear un diccionario
notas = {
"pepe" : 5,
"john" : 10,
"Vader": 8
}
#-- Recorrer diccionario obteniendo los
#-- pares clave/valor
for k,v in notas.items():
print(k, v)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$ ./01-diccioanrio.py
pepe 5
john 10
Vader 8
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$ Al iterar sobre una secuencia, obtenemos el índice usando el método enumerate:
#!/usr/bin/env python3
for i,v in enumerate(["obijuan", "vader", "yoda"]):
print(i, v)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$ ./02-enumerate.py
0 obijuan
1 vader
2 yoda
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$ Podemos iterar por varias listas usando la función zip:
!/usr/bin/env python3
canal1 = ["a1", "a2", "a3"]
canal2 = ["b1", "b2", "b3"]
for a,b in zip(canal1, canal2):
print("Par de muestras:", a, b)Resultado de la ejecución:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$ ./03-zip.py
Par de muestras: a1 b1
Par de muestras: a2 b2
Par de muestras: a3 b3
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-05
$Vamos a crear un módulo de ejemplo. En el fichero fibo.py situamos las funciones de fibonacci de ejemplo del tutorial:
#!/usr/bin/env python3
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return resultAhora desde el termial de python importamos el módulo fibo, y tenemos acceso a ambas funciones dentro del espacio de nombres fibo:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$ ipython3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.31.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import fibo
In [2]: fibo.fib(5)
0 1 1 2 3
In [3]: fibo.fib2(10)
Out[3]: [0, 1, 1, 2, 3, 5, 8]
In [4]:Tenemos acceso al nombre del módulo en: fibo.__name__
$ ipython3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.31.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import fibo
In [2]: fibo.__name__
Out[2]: 'fibo'
In [3]:
El espacio de nombres del módulo se puede renombrar al importarlo usando el comando as:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$ ipython3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.31.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import fibo as fib
In [2]: fib.fib(5)
0 1 1 2 3
In [3]: Al importar un módulo se ejecuta su código. Modificamos el módulo de fibonacci:
#!/usr/bin/env python3
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
#-- Codigo que se ejecuta al importar el modulo
print("--> Modulo Fibonacci")Ahora vemos el mensaje impreso en la consola al importarlo:
$ ipython3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.31.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import fibo as fib
--> Modulo Fibonacci
In [2]:También podemos ejecutar código sólo si se ejecuta el módulo directamente, y no al importarlo:
#!/usr/bin/env python3
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
#-- Codigo que se ejecuta al importar el modulo
print("--> Modulo Fibonacci")
if __name__ == '__main__':
import sys
print("Llamando a la función fib()...")
fib(int(sys.argv[1]))Ahora lo ejecutamos:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$ python3 fibo.py 10
--> Modulo Fibonacci
Llamando a la función fib()...
0 1 1 2 3 5 8
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$Varios módulos los podemos agrupar en un paquete. Creamos un directorio con el nombre del paquete. Y ahí situamos todos los ficheros .py que conforman los módulos. Además hay que añadir el fichero __init__.py (que puede estar vacío). Estas es la forma que tiene python de conocer que ese directorio es en realidad un paquete...
En este ejemplo situamos el módulo fibo.py dentro de la carpeta mi_paquete (y colocamos el fichero init.py)
#!/usr/bin/env python3
import mi_paquete.fibo
mi_paquete.fibo.fib(10)Este es el resultado al probarlo:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$ ./01-paquete.py
--> Modulo Fibonacci
0 1 1 2 3 5 8
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-06
$Es posible almacenar la posición actual del cursor mediante una secuencia ANSI. Y luego se puede situar el cursor en la posición almacenada. Vamos a preguntar a ChatGPT:
- PREGUNTA:
cual es la secuencia ansi para almacenar la posición actual del cursor, para recuperarla más adelante
- RESPUESTA
La secuencia de escape ANSI para almacenar la posición actual del cursor es "\033[s". Al enviar esta secuencia al terminal, se guarda la posición actual del cursor en una memoria temporal.
Para recuperar la posición del cursor guardada previamente, se utiliza la secuencia de escape "\033[u". Al enviar esta secuencia al terminal, el cursor se moverá a la posición guardada previamente por la secuencia "\033[s".
Por ejemplo, si se desea guardar la posición actual del cursor, se puede enviar la secuencia "\033[s". Luego, si se desea mover el cursor de vuelta a esa posición, se puede enviar la secuencia "\033[u". El cursor se moverá de vuelta a la posición guardada previamente.
#!/usr/bin/env python3
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\033[u"
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#── Nada más empezar se guarda la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
#-- Imprimir mensaje en primer linea
print("HolaHola")
#-- Recuperar la posicion del cursor
print(CURSOR_POP, end='', flush=True)
#-- Escribir puntos encima, para borrar los caracteres anteriores
print("...")Al ejecutarlo se ve esto:
obijuan@Hoth:~/Develop/Learn-python/Examples/ANSI
$ ./04-cursor-1.py
...aHola
obijuan@Hoth:~/Develop/Learn-python/Examples/ANSI
$
El mensaje original era "HolaHola", pero al escribirse "..." se machacan los tres primeros caracteres
Esto lo necesitamos para hacer animaciones básicas... Sin embargo hay todavía un problema: que el cursor se ve, y se aprecia movimiento. Esto lo podemos comprobar metiendo en un bucle infinito el ejemplo anterior:
#!/usr/bin/env python3
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\033[u"
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
#-- Imprimir mensaje en primer linea
print("HolaHola")
while True:
#-- Recuperar la posicion del cursor
print(CURSOR_POP, end='', flush=True)
#-- Escribir puntos encima, para borrar los caracteres anteriores
print("...")Vamos a buscar secuencias ASNI para que el cursor desaparezca:
- PREGUNTA:
cual es la secuencia ANSI para ocultar el cursor y hacer que aparezca de nuevo
- RESPUESTA:
La secuencia de escape ANSI para ocultar el cursor es "\033[?25l". Al enviar esta secuencia al terminal, el cursor desaparecerá de la pantalla.
Para hacer que el cursor aparezca de nuevo, se utiliza la secuencia de escape "\033[?25h". Al enviar esta secuencia al terminal, el cursor se mostrará de nuevo en la pantalla.
Por ejemplo, si se desea ocultar el cursor, se puede enviar la secuencia "\033[?25l". Luego, si se desea hacer que el cursor aparezca de nuevo, se puede enviar la secuencia "\033[?25h". El cursor volverá a mostrarse en la pantalla.
En este ejemplo ya se puede ver el ejemplo anterior pero sin el cursor:
#!/usr/bin/env python3
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
#-- Imprimir mensaje en primer linea
print("HolaHola")
try:
while True:
#-- Recuperar la posicion del cursor
print(CURSOR_POP, end='', flush=True)
#-- Escribir puntos encima, para borrar los caracteres anteriores
print("...")
except KeyboardInterrupt:
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)Con esto ya tenemos una primera base para hacer animaciones sencillas. La primera será una cuenta atrás
#!/usr/bin/env python3
import time
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#-- Ocultar cursor
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
for i in range(0,10):
print(i, CURSOR_POP, end='', flush=True)
time.sleep(1)
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)La siguiente animación es una barra de progreso, con caracteres unicode:
#!/usr/bin/env python3
import time
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#-- Ocultar cursor
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
#-- Imprimir plantilla barra de progreso
print("░" * 10)
print(CURSOR_POP, end='', flush=True)
for i in range(0,10):
print("█", end='', flush=True)
time.sleep(0.1)
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)Ahora hacemos una animación en 2D. La más pequeña es de 2x2 caracteres. Haremos que una pelota se mueve en sentido horario en esas cuatro posiciones. Definimos los 4 frames del sprite en una lista
#!/usr/bin/env python3
import time
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
def print_frame(frame):
"""Print a frame on the console
"""
#-- Print the frame, line by line
for line in frame:
print(line)
#──── The sprite is composed of frames
SPRITE = [
[
"● ", #-- Frame 0
" "
],
[
" ●", #-- Frame 1
" "
],
[
" ", #-- Frame 2
" ●"
],
[
" ", #-- Frame 3
"● "
]
]
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#-- Frame period, in seconds
WAIT = 0.2
#-- Ocultar cursor
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
try:
#-- La animación se repite hasta que se pulse Ctrl-C
while True:
#-- Imprimir todos los frames, uno tras otro
for frame in SPRITE:
print(CURSOR_POP, end='', flush=True)
print_frame(frame)
time.sleep(WAIT)
#── Se ha pulsado Ctrl-C: Terminar
except KeyboardInterrupt:
print()
print()
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)En la animación se ve al bola que se mueve en sentido horario
En esta otra se realiza una cuenta del 0 al 9 dibujando cada dígito como un sprite de 4x5 píxeles (iguales que los de alexa)
#!/usr/bin/env python3
import time
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
def print_frame(frame):
"""Print a frame on the console
"""
#-- Print the frame, line by line
for line in frame:
print(line)
#──── Sprite de digitos
DIGITOS = [
["●●●●", #-- Numero 0
"● ●",
"● ●",
"● ●",
"●●●●",],
[" ●", #-- Numero 1
" ●",
" ●",
" ●",
" ●"],
["●●●●", #-- Numero 2
" ●",
"●●●●",
"● ",
"●●●●"],
["●●●●", #-- Numero 3
" ●",
"●●●●",
" ●",
"●●●●"],
["● ●", #-- Numero 4
"● ●",
"●●●●",
" ●",
" ●"],
["●●●●", #-- Numero 5
"● ",
"●●●●",
" ●",
"●●●●"],
["● ", #-- Numero 6
"● ",
"●●●●",
"● ●",
"●●●●"],
["●●●●", #-- Numero 7
" ●",
" ●",
" ●",
" ●"],
["●●●●", #-- Numero 8
"● ●",
"●●●●",
"● ●",
"●●●●"],
["●●●●", #-- Numero 9
"● ●",
"●●●●",
" ●",
" ●"],
]
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#-- Frame period, in seconds
WAIT = 0.5
#-- Ocultar cursor
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
try:
#-- La animación se repite hasta que se pulse Ctrl-C
while True:
#-- Imprimir todos los frames, uno tras otro
for dig in DIGITOS:
print(CURSOR_POP, end='', flush=True)
print_frame(dig)
time.sleep(WAIT)
#── Se ha pulsado Ctrl-C: Terminar
except KeyboardInterrupt:
print()
print()
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)Este es el mismo ejemplo contador, pero con los dígitos dibujados con los caraceres Unicode de caja. Los números quedan más bonitos
#!/usr/bin/env python3
import time
#───────────────────────────────────────
# Definiciones ANSI para el cursor
#───────────────────────────────────────
#──── Almacenar la posicion actual del cursor
CURSOR_PUSH = "\x1B[s"
#──── Recuperar la posicion del cursor previamente guardada
CURSOR_POP = "\x1B[u"
#──── Ocultar el cursor
CURSOR_HIDE = "\x1B[?25l"
#──── Mostrar el cursor
CURSOR_SHOW = "\x1B[?25h"
def print_frame(frame):
"""Print a frame on the console
"""
#-- Print the frame, line by line
for line in frame:
print(line)
#──── Sprite de digitos
DIGITOS = [
["┌──┐", #-- Numero 0
"│ │",
"│ │",
"│ │",
"└──┘",],
[" ╷", #-- Numero 1
" │",
" │",
" │",
" ╵"],
["╶──┐", #-- Numero 2
" │",
"┌──┘",
"│ ",
"└──╴"],
["╶──┐", #-- Numero 3
" │",
"╶──┤",
" │",
"╶──┘"],
["╷ ╷", #-- Numero 4
"│ │",
"└──┤",
" │",
" ╵"],
["┌──╴", #-- Numero 5
"│ ",
"└──┐",
" │",
"╶──┘"],
["╷ ", #-- Numero 6
"│ ",
"├──┐",
"│ │",
"└──┘"],
["╶──┐", #-- Numero 7
" │",
" │",
" │",
" ╵"],
["┌──┐", #-- Numero 8
"│ │",
"├──┤",
"│ │",
"└──┘"],
["┌──┐", #-- Numero 9
"│ │",
"└──┤",
" │",
" ╵"],
]
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
#-- Frame period, in seconds
WAIT = 0.5
#-- Ocultar cursor
print(CURSOR_HIDE, end='', flush=True)
#── Guardar la posicion del cursor
print(CURSOR_PUSH, end='', flush=True)
try:
#-- La animación se repite hasta que se pulse Ctrl-C
while True:
#-- Imprimir todos los frames, uno tras otro
for dig in DIGITOS:
print(CURSOR_POP, end='', flush=True)
print_frame(dig)
time.sleep(WAIT)
#── Se ha pulsado Ctrl-C: Terminar
except KeyboardInterrupt:
print()
print()
##- Volver a hacer el cursor visible
print(CURSOR_SHOW)Una de las cosas que quiero hacer con python es un LEDOscopio, como el que se tiene implementado en la FPGA. Se le pasa un byte y debe dibujar los bits independientes
El primer programa es un simple conversor a binario. Hay que crear una función que reciba un byte y que devuelva una cadena con los bits
Pido ayuda a ChapGPT y tras un mini diálogo consigo lo que quiero. Reproduzco el diálogo:
- PREGUNTA: escribe un programa en python que convierta el número introducidor por el usuario a binario
- RESPUESTA:
¡Claro! Puedo ayudarte a escribir un programa en Python que convierta un número introducido por el usuario a binario. Aquí tienes un ejemplo de código:
# Pedir al usuario que ingrese un número entero
decimal = int(input("Introduce un número entero: "))
# Convertir a binario
binario = bin(decimal)
# Imprimir el resultado
print(f"El número {decimal} en binario es {binario}.")En este programa, utilizamos la función input() para pedirle al usuario que ingrese un número entero. Luego, usamos la función bin() para convertir el número decimal a binario. Finalmente, imprimimos el resultado con la función print().
Espero que esto te ayude. Si tienes alguna otra pregunta, ¡no dudes en preguntar!
- PREGUNTA: modifica el programa anterior para que los numeros en binarios tengan siempre 8 digitos
- RESPUESTA:
Claro, para modificar el programa anterior y hacer que el número binario tenga siempre 8 dígitos podemos utilizar el método str.zfill() que rellena con ceros a la izquierda una cadena de texto. Aquí te dejo el código modificado:
# Pedir al usuario que ingrese un número entero
decimal = int(input("Introduce un número entero: "))
# Convertir a binario y rellenar con ceros a la izquierda hasta tener 8 dígitos
binario = bin(decimal)[2:].zfill(8)
# Imprimir el resultado
print(f"El número {decimal} en binario es {binario}.")
> En este programa, utilizamos la función input() para pedirle al usuario que ingrese un número entero. Luego, usamos la función bin() para convertir el número decimal a binario. La parte [2:] se utiliza para quitar los primeros dos caracteres de la cadena que corresponden al prefijo 0b que indica que es un número binario. Finalmente, utilizamos el método str.zfill(8) para rellenar con ceros a la izquierda hasta tener 8 dígitos. Por último, imprimimos el resultado con la función print().- PREGUNTA: se puede hacer el mismo programa usando argumentos de la cadena f?
- RESPUESTA:
¡Claro que sí! Podemos utilizar los argumentos de la cadena f para hacer que el número binario tenga siempre 8 dígitos. Aquí te dejo el código modificado:
# Pedir al usuario que ingrese un número entero
decimal = int(input("Introduce un número entero: "))
# Convertir a binario y rellenar con ceros a la izquierda hasta tener 8 dígitos
binario = f'{decimal:b}'.zfill(8)
# Imprimir el resultado
print(f"El número {decimal} en binario es {binario}.")- PREGUNTA: existe un argumento similar al método str.zfill(8) pero usado en la cadena f?
- RESPUESTA:
Sí, existe un argumento similar al método str.zfill() que puedes usar en la cadena f. Se trata del especificador de ancho mínimo de campo, que se escribe como : dentro de la cadena de formato.
Este especificador permite establecer el ancho mínimo del campo en n caracteres, y si el valor resultante de la expresión es menor que n caracteres, se rellena con espacios en blanco a la izquierda para cumplir con el ancho mínimo.
Aquí te dejo el código modificado para usar el especificador de ancho mínimo de campo en la cadena f:
# Pedir al usuario que ingrese un número entero
decimal = int(input("Introduce un número entero: "))
# Convertir a binario
binario = f'{decimal:b}'
# Imprimir el resultado rellenando con ceros a la izquierda hasta tener 8 dígitos
print(f"El número {decimal} en binario es {binario:0>8}.")En este programa, utilizamos la función input() para pedirle al usuario que ingrese un número entero. Luego, utilizamos los argumentos de la cadena f para convertir el número decimal a binario con la cadena de formato '{decimal:b}'. La letra 'b' indica que queremos el número en su representación binaria. Luego, en la cadena de formato para imprimir el resultado, usamos el especificador :0>8 para rellenar con ceros a la izquierda hasta tener 8 dígitos. El 0 indica que queremos rellenar con ceros, el > indica que queremos justificar a la derecha, y el 8 indica que queremos un ancho mínimo de 8 caracteres.
El programa que queda al final es este:
#!/usr/bin/env python3
while True:
try:
#-- Pedir byte al usuario
num = int(input("Introduce byte (0-255): "))
#-- Imprimir en binario
print(f"{num:08b}")
except KeyboardInterrupt:
print()
print("Fin")
breakLa ejecución se termina con Ctrl-C. Este es el resultado de ejecución y varias conversiones:
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ ./01-byte-to-bin.py
Introduce byte (0-255): 3
00000011
Introduce byte (0-255): 128
10000000
Introduce byte (0-255): 255
11111111
Introduce byte (0-255): ^C
Fin
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ El siguiente paso es hacerlo un poco más bonito... una primera forma es usando los caracteres de barra baja para el 0 y el de bloque para el uno
- NOTA: En esta página se encuentra todos los caracteres unicode: https://symbl.cc/es/unicode/
Este es el programa. Se crea una cadena nueva reemplazando los símbolos '0' y '1' por los nuevos:
#!/usr/bin/env python3
while True:
try:
#-- Pedir byte al usuario
num = int(input("Introduce byte (0-255): "))
#-- Pasar el numero a una cadena binaria de 8 bits
cadbin = f"{num:08b}"
#-- Sustituir el bit 0 por otro caracter
cad = cadbin.replace('0','_').replace('1','▉')
print(cad)
except KeyboardInterrupt:
print()
print("Fin")
breakEste es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ ./02-byte-to-bin-2.py
Introduce byte (0-255): 255
▉▉▉▉▉▉▉▉
Introduce byte (0-255): 3
______▉▉
Introduce byte (0-255): 3
______▉▉
Introduce byte (0-255): 170
▉_▉_▉_▉_
Introduce byte (0-255): 171
▉_▉_▉_▉▉
Introduce byte (0-255): ^C
Fin
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$El siguiente paso es hacer que cada bit ocupe 3 caracteres para poder poner encima el número de ciclo
Este es el programa:
#!/usr/bin/env python3
while True:
try:
#-- Pedir byte al usuario
print()
num = int(input("Introduce byte (0-255): "))
#-- Pasar el numero a una cadena binaria de 8 bits
cadbin = f"{num:08b}"
#-- Sustituir el bit 0 por otro caracter
cad = cadbin.replace('0','___').replace('1','▐█▌')
#-- Imprimir
print()
print(" 0 1 2 3 4 5 6 7")
print(cad)
except KeyboardInterrupt:
print()
print("Fin")
breakY este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ ./03-Ledoscopio-1.py
Introduce byte (0-255): 1
0 1 2 3 4 5 6 7
_____________________▐█▌
Introduce byte (0-255): 3
0 1 2 3 4 5 6 7
__________________▐█▌▐█▌
Introduce byte (0-255): 255
0 1 2 3 4 5 6 7
▐█▌▐█▌▐█▌▐█▌▐█▌▐█▌▐█▌▐█▌
Introduce byte (0-255): 170
0 1 2 3 4 5 6 7
▐█▌___▐█▌___▐█▌___▐█▌___
Introduce byte (0-255): 85
0 1 2 3 4 5 6 7
___▐█▌___▐█▌___▐█▌___▐█▌
Introduce byte (0-255): ^C
Fin
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ El siguiente paso es hacer que se dibujen con caracteres unicode, y que tengan, al menos, 2 caracteres de alto. Se comienza con el bit del ciclo 0, que se dibujará de diferenes maneras según la transición que viene a continuación:
- "00": ────── ("──┴──┴") ┌───
- "01": ──┘ ──┐
- "10": └── ─────
- "11":
En realidad son más casos.. vamos a centrarnos en el bit "central", según los bits que tenga a la derecha y a la izquierda las posibilidades son:
- Bit central a 0:
0 0 0 0 0 1 1 0 0 1 0 1
┌── ──┐ ──┐ ┌───
───────── ──────┘ └────── └──┘
- Bit central a 1:
0 1 0 0 1 1 1 1 0 1 1 1
┌──┐ ┌────── ──────┐ ─────────
──┘ └─── ──┘ └───
Este es el programa para mostrar la señal:
#!/usr/bin/env python3
#-- Cadenas para dibujar las lineas superiores e inferiores de un bit
#-- de la señal
#-- Hay 4 casos que dependen del bit actual y del siguiente
BIT_LINE = {
#-- Linea superior
"superior" : [
' ', #-- 0: Caso "00"
' ┌', #-- 1: Caso "01"
'──┐', #-- 2: Caso "10"
'───' #-- 3: Caso "11"
],
#-- Linea inferior
"inferior": [
'───', #-- 0: Caso "00"
'──┘', #-- 1: Caso "01"
' └', #-- 2: Caso "10"
' ', #-- 3: Caso "11"
]
}
def print_wave(cadbin : str) -> None:
"""Imprimir la señal asociada a la cadena de bits"""
#-- Duplicar el último bit (hay 9 bits)
cadbin += cadbin[-1]
#-- Cadena superior
cadT = ""
#-- Cadena inferior
cadB = ""
#-- Recorrer todos los bits para calcular las cadenas
#-- superior e inferior
#-- (hay 8 bits de datos a representar)
for i in range(8):
#-- Convertir el bit actual y el siguiente en un numero entero
num = int(cadbin[i] + cadbin[i+1], 2)
#-- Añadir las cadenas del bit actual
cadT += BIT_LINE["superior"][num]
cadB += BIT_LINE["inferior"][num]
#-- Imprimir la señal
print (cadT) #-- Parte superior
print (cadB) #-- Parte inferior
#───────────────────────────────────────
# MAIN
#───────────────────────────────────────
while True:
try:
#-- Pedir byte al usuario
print()
num = int(input("Introduce byte (0-255): "))
#-- Si se pulsa Ctrl-C --> Terminar
except KeyboardInterrupt:
print()
print("Fin")
break
#-- Pasar el numero a una cadena binaria de 8 bits
cadbin = f"{num:08b}"
#-- Imprimir la señal
print()
print(" 0 1 2 3 4 5 6 7")
print_wave(cadbin)Y este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ ./04-Ledoscopio-2.py
Introduce byte (0-255): 170
0 1 2 3 4 5 6 7
──┐ ┌──┐ ┌──┐ ┌──┐
└──┘ └──┘ └──┘ └───
Introduce byte (0-255): 85
0 1 2 3 4 5 6 7
┌──┐ ┌──┐ ┌──┐ ┌───
──┘ └──┘ └──┘ └──┘
Introduce byte (0-255): 1
0 1 2 3 4 5 6 7
┌───
────────────────────┘
Introduce byte (0-255): 255
0 1 2 3 4 5 6 7
────────────────────────
Introduce byte (0-255): 128
0 1 2 3 4 5 6 7
──┐
└─────────────────────
Introduce byte (0-255): ^C
Fin
obijuan@Hoth:~/Develop/Learn-python/Examples/LEDOscopio
$ La manera más cómoda para formatear la información de salida es usando cadenas f. Aquí se muestran varios ejemplos de los usos típicos
#!/usr/bin/env python3
num = 35
cad = "Hola"
#-- Imprimir las variables
print(f"Variable num: {num}, Variable cad: {cad}")
#-- Establecer una anchura máxima
print(f"Variable num: {num:10}, Variable cad: {cad:10}---")
#-- Mostrar el valor para depuración
print(f"Debug: {num=}, {cad=}")
#-- Imprimir numeros en base diferente
print(f"Num: Decial: {num:d}, Hexa: {num:x}, Binario: {num:b}----")
#-- Establecer tamaño maximo para numeros
print(f"Num: Decial: {num:5d}, Hexa: {num:4x}, Binario: {num:8b}----")
#-- Rellenar con 0s la izquierda
print(f"Num: Decial: {num:05d}, Hexa: {num:04x}, Binario: {num:08b}----")Esta es la salida:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./01-f-strings-1.py
Variable num: 35, Variable cad: Hola
Variable num: 35, Variable cad: Hola ---
Debug: num=35, cad='Hola'
Num: Decial: 35, Hexa: 23, Binario: 100011----
Num: Decial: 35, Hexa: 23, Binario: 100011----
Num: Decial: 00035, Hexa: 0023, Binario: 00100011----
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ Las cadenas tienen los siguientes métodos para formatear:
- .rjust() -> Justificación a la derecha
- .ljust() -> Justificación a la izquierda
- .center() -> Centrar
- .zfill() -> Rellenar una cadena numerica con 0s a la izquierda
#!/usr/bin/env python3
num = 35
cad = "Hola"
#-- Imprimir las variables
print(f"Variable num: {num}, Variable cad: {cad}")
#-- Establecer una anchura máxima
print(f"Variable num: {num:10}, Variable cad: {cad:10}---")
#-- Mostrar el valor para depuración
print(f"Debug: {num=}, {cad=}")
#-- Imprimir numeros en base diferente
print(f"Num: Decial: {num:d}, Hexa: {num:x}, Binario: {num:b}----")
#-- Establecer tamaño maximo para numeros
print(f"Num: Decial: {num:5d}, Hexa: {num:4x}, Binario: {num:8b}----")
#-- Rellenar con 0s la izquierda
print(f"Num: Decial: {num:05d}, Hexa: {num:04x}, Binario: {num:08b}----")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./02-str-methods.py
* Hola*
*Hola *
* Hola *
*00576*
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ Conviene siempre utilizar with para que se cierre automáticamente el fichero (incluso cuando ocurre una excepción)
En este ejemplo se lee el contenido del fichero file1.txt y se imprime en la consola. La apertura de los ficheros, por defecto, es en modo lectura:
#!/usr/bin/env python3
#-- Ejemplo de apertura de un fichero de texto
#-- para su lectura
with open("file1.txt", encoding="utf-8") as f:
text = f.read()
print()
print("CONTENIDO DEL FICHERO:")
print("──────────────────────")
print(text)
print("──────────────────────")
Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./03-files-read-text.py
CONTENIDO DEL FICHERO:
──────────────────────
Fichero de texto de prueba
Holi
Linea 3...
Linea 4...
Fin
──────────────────────
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$Y este es un ejemplo de creación del fichero file2.txt:
#!/usr/bin/env python3
FICHERO = "file2.txt"
#-- Ejemplo de apertura de un fichero de texto
#-- para escritura
with open("file2.txt", "w", encoding="utf-8") as f:
f.write("Fichero de texto creado\n")
f.write("Linea 1....\n")
f.write("Linea 2...\n")
f.write("Linea 3...\n")
print(f"Fichero {FICHERO} creado")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ cat file2.txt
Fichero de texto creado
Linea 1....
Linea 2...
Linea 3...
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$También se pueden leer fichero en binario. Para ello primero creamos uno desde la consola con el comando:
echo -ne "\x00\x01\x02\x03\xFF" > test1.bin
Nos crea el archivo binario test1.bin de 5 bytes
Ahora lo leemos con el siguiente programa:
#!/usr/bin/env python3
FICHERO = "test1.bin"
#-- Ejemplo de apertura de un fichero binario
#-- para lectura
with open(FICHERO, "rb") as f:
data = f.read()
print()
print(f"CONTENIDO FICHERO {FICHERO}:")
print(f"Tamaño: {len(data)} bytes")
print("──────────────────────")
print(data)
print("──────────────────────")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./05-files-read-bin.py
CONTENIDO FICHERO test1.bin:
Tamaño: 5 bytes
──────────────────────
b'\x00\x01\x02\x03\xff'
──────────────────────
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$Los bytes se imprimen como una cadena de tipo raw, que empieza por b. El carácter \x indica que están en hexadecimal
En este ejemplo se imprimen los byes como cadenas en hexadecimal de dos dígitos:
#!/usr/bin/env python3
FICHERO = "test1.bin"
#-- Ejemplo de apertura de un fichero binario
#-- para lectura
with open(FICHERO, "rb") as f:
data = f.read()
#-- Pasar los bytes a cadenas de numeros hexadecimales
data_hex = [f"{byte:02x}" for byte in data]
print()
print(f"CONTENIDO FICHERO {FICHERO}:")
print(f"Tamaño: {len(data)} bytes")
print("──────────────────────")
print(" ".join(data_hex))
print("──────────────────────")Este es el nuevo resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./06-files-read-bin-2.py
CONTENIDO FICHERO test1.bin:
Tamaño: 5 bytes
──────────────────────
00 01 02 03 ff
──────────────────────
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$Para crear un fichero binario con una serie de bytes lo hacemos así:
#!/usr/bin/env python3
FICHERO = "test2.bin"
#-- Cadena con los bytes a escribir
bytes = b"\x00\x01\x02\x03\xFF"
#-- Ejemplo de escritura de un fichero binario
with open(FICHERO, "wb") as f:
f.write(bytes)
print(f"Fichero {FICHERO} creado")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./07-files-write-bin.py
Fichero test2.bin creado
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ hd test2.bin
00000000 00 01 02 03 ff |.....|
00000005
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ls -l test2.bin
-rw-rw-r-- 1 obijuan obijuan 5 abr 3 12:09 test2.bin
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ También podemos definir los bytes en una lista y convertirlos al tipo bytes con la función bytes:
#!/usr/bin/env python3
FICHERO = "test2.bin"
#-- Cadena con los bytes a escribir
bytes = bytes([0x00, 0x01, 0x02, 0x03, 0xFF])
#-- Ejemplo de escritura de un fichero binario
with open(FICHERO, "wb") as f:
f.write(bytes)
print(f"Fichero {FICHERO} creado")El resultado es equivalente al ejemplo anterior
El módulo json se utiliza para pasar estructuras de datos a JSON. En este ejemplo definimos una lista y un diccionario y lo pasamos a JSON (que se podría guardar en un fichero de texto para su uso)
#!/usr/bin/env python3
import json
FICHERO1 = "list.json"
FICHERO2 = "objeto.json"
#-- Ejemplo de lista
lista = ["holi", 2, 3, "vamos"]
#-- Ejemplo de diccionario (objeto)
objeto = {
"nombre": "test",
"id": 234
}
#-- Pasar a JSON
lista_json = json.dumps(lista)
objeto_json = json.dumps(objeto)
#-- Imprimir sus correspondientes representaciones en JSON
print(lista_json)
print(objeto_json)
#-- Crear dos ficheros en JSON
with open(FICHERO1, "w", encoding="utf-8") as f:
f.write(lista_json)
print(f"Creado fichero {FICHERO1}")
with open(FICHERO2, "w", encoding="utf-8") as f:
f.write(objeto_json)
print(f"Creado fichero {FICHERO2}")Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./09-json-1.py
["holi", 2, 3, "vamos"]
{"nombre": "test", "id": 234}
Creado fichero list.json
Creado fichero objeto.jsonEste es un ejemplo de lectura del fichero json lista.json:
#!/usr/bin/env python3
import json
FICHERO1 = "list.json"
#-- Leer directamente el fichero json
with open(FICHERO1, encoding='utf-8') as f:
lista = json.load(f)
#-- Sabemos que el objeto es una lista...
#-- la iteramos e imprimimos su contenido
for e in lista:
print(e)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$ ./10-json-2.py
holi
2
3
vamos
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-07
$El formato JSON es el que utiliza icestudio, así que le voy a dedicar ejemplos especiales
Vamos a frikear con el JSON de icestudio. La idea es crear herramientas en la línea de comandos para procesar los ficheros .ice de icestudio. Esto es algo qu empecé a hacer en este repo:
https://github.com/FPGAwars/Icestudio-cli
Pero de momento haremos ejemplos sencillos en python y más adelante se integrarán en ese repositorio o en uno nuevo
Empezamos examinado el json de un fichero icestudio "vacio"...
{
"version": "1.2",
"package": {
"name": "",
"version": "",
"description": "",
"author": "",
"image": ""
},
"design": {
"board": "alhambra-ii",
"graph": {
"blocks": [],
"wires": []
}
},
"dependencies": {}
}El fichero .ice es un objeto que tiene 4 propiedades:
- Versión: Usada para indicar la versión del formato de icestudio
- Package: Información sobre el proyecto: nombre, autor, descripción...
- Design: Implementación del diseño: Placa y grafo de circuito
- Dependencies: Bloques usados para la implementación del circuito
En este primero ejemplo vamos a leer un fichero de Icestudio e imprimir información básica:
#!/usr/bin/env python3
import json
#-- Fichero .ice a leer
ICE_FILE = "01-vacio.ice"
#-- Constantes asociadas a las propiedades del .ice
VERSION = "version"
DESIGN = "design"
BOARD = "board"
#-- Leer circuito. Accesible desde el objeto "top"
with open(ICE_FILE) as f:
top = json.load(f)
#-- Imprimir información
print(f"Version: {top[VERSION]}")
print(f"Placa: {top[DESIGN][BOARD]}")Al ejecutarlo obtenemos esto:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./01-ice-lectura-vacio.py
Version: 1.2
Placa: alhambra-ii
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ Los circuitos están formados por un grafo, que consiste en una lista de bloques y otra de cables. Este es un circuito de icestudio que sólo contiene un bloque de información (y nada más):
"version": "1.2",
"package": {
"name": "",
"version": "",
"description": "",
"author": "",
"image": ""
},
"design": {
"board": "alhambra-ii",
"graph": {
"blocks": [
{
"id": "84395e4e-e7cb-421c-bb47-b60ba6dc529b",
"type": "basic.info",
"data": {
"info": "Hola",
"readonly": false
},
"position": {
"x": 560,
"y": 240
},
"size": {
"width": 192,
"height": 128
}
}
],
"wires": []
}
},
"dependencies": {}
}Este programa en python obtiene la lista de bloques y de cables e imprime su número:
#!/usr/bin/env python3
import json
#-- Fichero .ice a leer
ICE_FILE = "02-info-1.ice"
#-- Constantes asociadas a las propiedades del .ice
VERSION = "version"
DESIGN = "design"
BOARD = "board"
GRAPH = "graph"
BLOCKS = "blocks"
WIRES = "wires"
#-- Leer circuito. Accesible desde el objeto "top"
with open(ICE_FILE) as f:
top = json.load(f)
#-- Obtener el grafo del circuito
grafo = top[DESIGN][GRAPH]
#-- Obtener la lista de bloques y cables
bloques = grafo[BLOCKS]
cables = grafo[WIRES]
num_blocks = len(bloques)
num_wires = len(cables)
#-- Imprimir información
print(f"Version: {top[VERSION]}")
print(f"Placa: {top[DESIGN][BOARD]}")
print(f"Cables: {num_wires}")
print(f"Bloques: {num_blocks}")Al ejecutarlo obtenemos esto:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./02-ice-lectura-info.py
Version: 1.2
Placa: alhambra-ii
Cables: 0
Bloques: 1
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$En este siguiente ejemplo se recorren los bloques y se imprime informacion sobre ellos:
#!/usr/bin/env python3
import json
#-- Fichero .ice a leer
ICE_FILE = "02-info-1.ice"
#-- Constantes asociadas a las propiedades del .ice
VERSION = "version"
DESIGN = "design"
BOARD = "board"
GRAPH = "graph"
BLOCKS = "blocks"
WIRES = "wires"
ID = "id"
TYPE = "type"
#-- Leer circuito. Accesible desde el objeto "top"
with open(ICE_FILE) as f:
top = json.load(f)
#-- Obtener el grafo del circuito
grafo = top[DESIGN][GRAPH]
#-- Obtener la lista de bloques y cables
bloques = grafo[BLOCKS]
cables = grafo[WIRES]
num_blocks = len(bloques)
num_wires = len(cables)
#-- Imprimir información
print(f"Version: {top[VERSION]}")
print(f"Placa: {top[DESIGN][BOARD]}")
print(f"Cables: {num_wires}")
print(f"Bloques: {num_blocks}")
#-- Recorrer los bloques
for block in bloques:
print(f" * Bloque id: {block[ID]}")
print(f" * Tipo: {block[TYPE]}")
print(f" * Posicion: {block['position']}")
print(f" * Tamaño: {block['size']}")Al ejecutarlo se obtiene esto:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./03-ice-lectura-info-2.py
Version: 1.2
Placa: alhambra-ii
Cables: 0
Bloques: 1
* Bloque id: 84395e4e-e7cb-421c-bb47-b60ba6dc529b
* Tipo: basic.info
* Posicion: {'x': 560, 'y': 240}
* Tamaño: {'width': 192, 'height': 128}
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ Voy a ir poco a poco modelando cada elemento como una clase. Empezamos por la clase tamaño (Size) que contiene dos propiedades: anchura y algura
#!/usr/bin/env python3
import json
#-- Constantes asociadas a las propiedades del .ice
VERSION = "version"
DESIGN = "design"
BOARD = "board"
GRAPH = "graph"
BLOCKS = "blocks"
WIRES = "wires"
ID = "id"
TYPE = "type"
SIZE = "size"
class Size:
"""Tamaño de los bloques de icestudio"""
def __init__(self, width, height) -> None:
"""Crear un objeto Size a partir de numeros enteros"""
self.width = width
self.height = height
def __init__(self, size: dict) -> None:
"""Crear un objeto Size a partir de un diccionario"""
self.width = size['width']
self.height = size['height']
def obj(self) -> dict:
"""Devolver el objeto (diccionario) que contiene los datos"""
return {
"width" : self.width,
"height": self.height
}
def __str__(self):
"""Devolver la cadena imprimible"""
return f'Size({self.width}, {self.height})'
#-- Fichero .ice a leer
ICE_FILE = "02-info-1.ice"
#-- Leer circuito. Accesible desde el objeto "top"
with open(ICE_FILE) as f:
top = json.load(f)
#-- Obtener tamaño del primer bloque
size = Size(top[DESIGN][GRAPH][BLOCKS][0][SIZE])
#-- Imprimir información
print(f"Version: {top[VERSION]}")
print(f"Placa: {top[DESIGN][BOARD]}")
print(f"Cables: {len(top[DESIGN][GRAPH][WIRES])}")
print(f"Bloques: {len(top[DESIGN][GRAPH][BLOCKS])}")
print(f" * Tamaño: {size}")Lo ejecutamos:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./04-ice-size-1.py
Version: 1.2
Placa: alhambra-ii
Cables: 0
Bloques: 1
* Tamaño: Size(192, 128)
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ Ahora vamos a encapsular la lectura del circuito en la clase Ice
#!/usr/bin/env python3
import json
#-- Constantes asociadas a las propiedades del .ice
VERSION = "version"
PACKAGE = "package"
DESIGN = "design"
DEPENDENCIES = "dependencies"
BOARD = "board"
GRAPH = "graph"
BLOCKS = "blocks"
WIRES = "wires"
ID = "id"
TYPE = "type"
SIZE = "size"
class Ice:
def __init__(self, file: str=None) -> None:
"""Crear un objeto circuito a partir de un fichero .ice"""
if file:
#-- Leer el archivo .ice
with open(file) as f:
self._top = json.load(f)
else:
self._top = {
"version": "1.2",
"package": {
"name": "",
"version": "",
"description": "",
"author": "",
"image": ""
},
"design": {
"board": "alhambra-ii",
"graph": {
"blocks": [],
"wires": []
}
},
"dependencies": {}
}
@property
def version(self):
return self._top[VERSION]
@property
def package(self):
return self._top[PACKAGE]
@property
def design(self):
return self._top[DESIGN]
@property
def dependencies(self):
return self._top[DEPENDENCIES]
def __str__(self):
cad = ""
cad += f"Version: {ice.version}\n"
cad += f"Placa: {ice.design[BOARD]}\n"
cad += f"Cables: {len(ice.design[GRAPH][WIRES])}\n"
cad += f"Bloques: {len(ice.design[GRAPH][BLOCKS])}\n"
cad += f" * Tamaño: {ice.design[GRAPH][BLOCKS][0][SIZE]}\n"
return cad
#-- Leer circuito
ice = Ice("02-info-1.ice")
#-- Imprimir información
print(ice)Este es el resultado:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./05-ice-top.py
Version: 1.2
Placa: alhambra-ii
Cables: 0
Bloques: 1
* Tamaño: {'width': 192, 'height': 128}
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ Ahora nos llevamos la clase Ice al fichero Icestudio.py. El ejemplo anterior queda mucho más limpio:
#!/usr/bin/env python3
from Icestudio import Ice
#-- Leer circuito
top = Ice("02-info-1.ice")
#-- Imprimir información
print(top)Lo ejecutamos:
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$ ./06-ice-top-2.py
Version: 1.2
Placa: alhambra-ii
Cables: 0
Bloques: 1
* Tamaño: {'width': 192, 'height': 128}
obijuan@Hoth:~/Develop/Learn-python/Examples/JSON
$Creo que esta parte la voy a continuar en el repositorio de Icestudio-cli:
https://github.com/FPGAwars/Icestudio-cli
Estoy refactorizando Apio. Para ello necesito entender bien la función subprocess.Popen()... así que voy a hacer ejemplo en este repo...
Documentación sobre subprocess.Popen(): https://docs.python.org/3/library/subprocess.html
Voy a aprovechar para empezar los ejemplos del capítulo 10
Enlace al tutorial:
https://docs.python.org/3/tutorial/stdlib.html
Lo interesante de la biblioteca estándard es que viene con python. NO hay que instalar nada adicional
El módulo os tiene muchas funciones para interactuar con el sistema operativo. Por ejemplo obtener el directorio de trabajo (getcwd) o cambiar de directorio (chdir) o ejecutar cualquier otro comando en la consola: system
Todos elllos retornan 0 si todo ha ido ok. Si el resultado es diferente de 0, ha ocurrido un error, con ese número (!=0) como código de error
#!/usr/bin/env python3
import os
#-- Imprimir el directorio actual
print(f"Directorio actual: {os.getcwd()}")
#-- Subir de directorio
os.chdir("..")
#-- Imprimir el directorio actual
print(f"Directorio actual: {os.getcwd()}")
#-- Ejecutar un comando en la consola
ret = os.system('echo "hola"')
#-- Resultado
#-- Si ret es 0, todo ha ido bien...
if ret==0:
print("OK!!")
#-- Ejecutamos un comando incorrecto
ret = os.system('fakeee')
if ret!=0:
print("ERROR!!!!!")Este es el resultado:
Directorio actual: /home/obijuan/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
Directorio actual: /home/obijuan/Develop/Learn-python/Examples/Python-tutorial
hola
OK!!
sh: 1: fakeee: not found
ERROR!!!!!https://docs.python.org/3/tutorial/stdlib.html
El módulo shutil contiene funciones de más alto nivel para la gestión de archivos: copiar, mover...
#!/usr/bin/env python3
import shutil
shutil.copyfile('test/data1.txt', 'test/data2.txt')
shutil.move('test/data2.txt', 'test/data3.txt')El módulo glob permite obtener lista de ficheros utilizando expresiones con comodines
#!/usr/bin/env python3
import glob
#-- Leer ficheros python
python_files = glob.glob('*.py')
#-- Imprimir lista de ficheros python
print(python_files)Esto es lo que se obitene al ejecutarlo:
['03-module-glob.py', '01-module-os.py', '02-module-shutil.py']La biblioteca sys permite leer los argumentos pasados como parámetros al ejecutar el programa desde la línea de comandos. Para pasar argumentos desde el vscode hay que añadir la propiedad args en el fichero 'launch.json'
{
"version": "0.2.0",
"configurations": [
{
"name": "Python RUN",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"args": ["holi"],
"console": "internalConsole",
//"console": "integratedTerminal",
//"console": "externalTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}/${relativeFileDirname}"
}
]
}Este programa imprime todos los parámetros pasados:
#!/usr/bin/env python3
import sys
#-- Imprimir la lista de argumentos pasados
print(sys.argv)Y esta la salida:
['/home/obijuan/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10/04-module-sys.py', 'holi']El módulo 'argparse' permite trabajar con los parámetros más fácilmente
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser(
prog='top',
description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)
print(f"* Argumento lines: {args.lines}")
print(f"* Argumento filenames: {args.filenames}")Si se ejecuta el programa sin argumentos sale esto:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
$ ./05-module-argparse.py
usage: top [-h] [-l LINES] filenames [filenames ...]
top: error: the following arguments are required: filenamesAhora le pasamos los argumentos:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
$ ./05-module-argparse.py fich1.txt fich2.txt --lines 8
Namespace(filenames=['fich1.txt', 'fich2.txt'], lines=8)
* Argumento lines: 8
* Argumento filenames: ['fich1.txt', 'fich2.txt']Para imprimir en la salida de error usamos sys.stderr y para la salida normal: sys.stdout. También tenemos sys.stdin. Para terminar se utiliza sys.exit()
#!/usr/bin/env python3
import sys
#-- Sacar por la consola estandar
sys.stdout.write("Salida normal\n")
#-- Sacar por la salida de error
sys.stderr.write('Error!!\n')
#-- Terminar
sys.exit()Si lo ejecutamos tal cual se ven los dos mensajes:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
$ ./06-module-sys-stderr.py
Salida normal
Error!!Pero ahora podemos distinguir entre los tipos de mensajes. Para que no salga el mensaje normal:
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
$ ./06-module-sys-stderr.py > /dev/null
Error!!Aquí no sale el mensaje de error
obijuan@Hoth:~/Develop/Learn-python/Examples/Python-tutorial/Capitulo-10
$ ./06-module-sys-stderr.py 2> /dev/null
Salida normal#!/usr/bin/env python3
import subprocess
#-- Ejecutar "ls -l". La salida no se captura
result1 = subprocess.run(["ls", "-l"])
print(f"{result1.args=}")
print(f"{result1.returncode=}")
print(f"{result1.stdout=}")
print()
#-- Ejecutar "ls -l". Capturando la salida
result2 = subprocess.run(["ls", "-l"], capture_output=True)
print(f"{result2.args=}")
print(f"{result2.returncode=}")
print(f"{result2.stdout=}")
print()
#-- Esto tambien captura la salida
result3 = subprocess.run(["ls", "-l"], stdout=subprocess.PIPE)
print(f"{result3.args=}")
print(f"{result3.returncode=}")
print(f"{result3.stdout=}")
print(result3)Este es el resultado:
total 4
-rwxrwxr-x 1 obijuan obijuan 623 feb 16 20:46 01-Subprocess.py
result1.args=['ls', '-l']
result1.returncode=0
result1.stdout=None
result2.args=['ls', '-l']
result2.returncode=0
result2.stdout=b'total 4\n-rwxrwxr-x 1 obijuan obijuan 623 feb 16 20:46 01-Subprocess.py\n'
result3.args=['ls', '-l']
result3.returncode=0
result3.stdout=b'total 4\n-rwxrwxr-x 1 obijuan obijuan 623 feb 16 20:46 01-Subprocess.py\n'
CompletedProcess(args=['ls', '-l'], returncode=0, stdout=b'total 4\n-rwxrwxr-x 1 obijuan obijuan 623 feb 16 20:46 01-Subprocess.py\n')Sigo trabajando en el tutorial de python. Esta es la configuración que tengo actualmente en el fichero launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python RUN",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"args": ["-l", "5", "fichero"],
"console": "internalConsole",
//"console": "integratedTerminal",
//"console": "externalTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}/${relativeFileDirname}"
}
]
}Esta es la configuración que voy a utilizar por defecto:
{
"version": "0.2.0",
"configurations": [
{
//-- Nombre de la configuracion
"name": "RUN file",
//-- Depurador de Python
"type": "debugpy",
//-- Lanzar el depurador
"request": "launch",
//-- Programa a depurar: Fichero en la pestaña activa
"program": "${file}",
//-- Dónde lanzar el depurador
"console": "internalConsole",
//-- Depurar sólo el código del usuario (no del sistema)
"justMyCode": true,
//-- Directorio de trabajo donde ejecutar el programa
"cwd": "${workspaceFolder}/${relativeFileDirname}"
}
]
}Guardamos el fichero actualizado. Ahora al irnos a la parte de depuración nos aparece en la parte superior el nombre de la nueva configuración RUN File. Abrimos la consola del depurador (View/Debub Console) y Pinchamos en el botón de Play para ejecutarlo

Voy a leer con calma este documento, para aprender más sobre la depuración en python y el concepto de depurador remoto, que no lo tengo claro
https://code.visualstudio.com/docs/python/debugging
También voy a leer la extensión oficial de depuración de python:
https://marketplace.visualstudio.com/items?itemName=ms-python.debugpy
Hablan sobre debugpy... quiero saber más sobre esto. Resulta que es un paquete de pypi:
https://pypi.org/project/debugpy/
Aquí está en el github:
https://github.com/microsoft/debugpy/
Tal vez una buena manera de empezar es utilizando el depurador desde la línea de comandos. Hay que instalar debugpy:
python -m pip install --upgrade debugpyPara que no se ponga pesado con los entornos virtuales, ejecuto este comando:
python -m pip install --upgrade debugpy --break-system-packagesComprobamos que se ha instalado bien:
obijuan@JANEL:~$ python -m debugpy
0.00s - Debugger warning: It seems that frozen modules are being used, which may
0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
0.00s - to python to disable frozen modules.
0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.
debugpy 1.8.12
See https://aka.ms/debugpy for documentation.
Usage: debugpy --listen | --connect
[<host>:]<port>
[--wait-for-client]
[--configure-<name> <value>]...
[--log-to <path>] [--log-to-stderr]
<filename> | -m <module> | -c <code> | --pid <pid>
[<arg>]...
Error: missing target: <filename> | -m <module> | -c <code> | --pid <pid>
obijuan@JANEL:~$Desde un terminal externo podemos ejecutar este comando:
obijuan@JANEL:~/Develop/Learn-python/wiki/L1/Ejemplos$ python -m debugpy --listen 5678 ./hola_mundo.py
0.00s - Debugger warning: It seems that frozen modules are being used, which may
0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
0.00s - to python to disable frozen modules.
0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.
Hola mundo
obijuan@JANEL:~/Develop/Learn-python/wiki/L1/Ejemplos$Lanza el depurador, que queda escuchando en el puerto 5678, y ejecuta el script hola_mundo.py
Si se ejecuta con el parámetro --wait-for-client, se lanza el servidor de depuración pero no ejecuta el hola_mundo.py hasta que se conecte un cliente
obijuan@JANEL:~/Develop/Learn-python/wiki/L1/Ejemplos$ python -m debugpy --listen 5678 --wait-for-client ./hola_mundo.py
0.00s - Debugger warning: It seems that frozen modules are being used, which may
0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
0.00s - to python to disable frozen modules.
0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.Ahora que ya tengo claro el funcionamiento de la arquitectura del depurador me apetece hacer experimentos de programación en python entre clientes y servidor, siguiendo los ejemplos del curso de Programación en entornos de red
El ejemplo 1 es un happy-server. Espera a que se conecte un cliente, imprime un mensaje y termina. Lo interesante es que le he dado al depurador al botón de ejecutar (play) y se ha conectado al servidor!!!!
He hecho un segundo ejemplo que espera recibir un mensaje del cliente que se conecta y lo imprime en la consola. Este es el resultado:
obijuan@JANEL:~/Develop/Learn-python/Examples/PNE$ python3 02-happy-server-02.py
Servidor escuchando en el puerto: 5678
Esperando conexiones...
Cliente conectado!!!
Content-Length: 542
{"command":"initialize","arguments":{"clientID":"vscode","clientName":"Visual Studio Code","adapterID":"debugpy","pathFormat":"path","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"locale":"en","supportsProgressReporting":true,"supportsInvalidatedEvent":true,"supportsMemoryReferences":true,"supportsArgsCanBeInterpretedByShell":true,"supportsMemoryEvent":true,"supportsStartDebuggingRequest":true,"supportsANSIStyling":true},"type":"request","seq":1}
obijuan@JANEL:~/Develop/Learn-python/Examples/PNE$El VSCode manda un objeto json. Lo voy a poner formateado:
{
"command":"initialize",
"arguments": {
"clientID":"vscode",
"clientName":"Visual Studio Code",
"adapterID":"debugpy",
"pathFormat":"path",
"linesStartAt1":true,
"columnsStartAt1":true,
"supportsVariableType":true,
"supportsVariablePaging":true,
"supportsRunInTerminalRequest":true,
"locale":"en",
"supportsProgressReporting":true,
"supportsInvalidatedEvent":true,
"supportsMemoryReferences":true,
"supportsArgsCanBeInterpretedByShell":true,
"supportsMemoryEvent":true,
"supportsStartDebuggingRequest":true,
"supportsANSIStyling":true
},
"type":"request",
"seq":1
}Voy a empezar a preparar la sesión L2, sobre Salida por consola. Voy a empezar a organizar los contenidos y ver exactamente qué incluir
Los teletipos permitían la comunicación punto a punto entre dos localizaciones separadas. Lo que recibe el teletipo lo "imprime" en papel, de izquierda a derecha, como una máquina de escribir
https://es.wikipedia.org/wiki/T%C3%A9lex#/media/Archivo:Telexmaskin.jpg
Un tío que se ha logeado a ubuntu con un teletipo:
https://x.com/MattisLind/status/1147488665192587264
Este tío es un crack de lo retro. Tienen montón de cosas interesantes:
Todo esto me ha llevado a estudiar la evolución de las ideas hasta llegar al terminal. Esta parte de la documentación la estoy escribiendo aquí: Terminales
TODO
https://docs.python.org/3/tutorial/errors.html
Unit tests: https://docs.python.org/3/library/unittest.html
- La biblioteca estándar para unit tests es unittest
- Existe también pytest (de terceros): https://docs.pytest.org/en/stable/
- secuencias ansi para desplazamientos del cursor: arriba, abajo, derecha, izquierda