# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Introducción
# Este curso cubre las habilidades clave de Python que necesitará para que pueda comenzar a usar Python para la ciencia de datos. El curso es ideal para alguien con experiencia previa en codificación que quiera agregar Python a su repertorio o subir de nivel sus habilidades básicas de Python. (Si es un programador por primera vez, puede consultar estos recursos de aprendizaje "Python para no programadores").
#
# Comenzaremos con una breve descripción general de la sintaxis de Python, la asignación de variables y los operadores aritméticos. Si tiene experiencia previa en Python, puede pasar directamente al ejercicio práctico.

# ## Hello, Python!
# Python fue nombrado por la compañía de comedia británica Monty Python, por lo que haremos de nuestro primer programa Python un homenaje a su parodia sobre el spam.
#
# Solo por diversión, intente leer el código a continuación y predecir lo que hará cuando se ejecute. (Si no tienes idea, ¡está bien!)
#
# Luego haga clic en el botón "salida" para ver los resultados de nuestro programa.

# +
spam_amount = 0
print(spam_amount)

# Ordering Spam, egg, Spam, Spam, bacon and Spam (4 more servings of Spam)
spam_amount = spam_amount + 4

if spam_amount > 0:
    print("But I don't want ANY spam!")

viking_song = "Spam " * spam_amount
print(viking_song)
# -

# ¡Hay mucho que desempacar aquí! Este programa tonto demuestra muchos aspectos importantes de cómo se ve el código Python y cómo funciona. Revisemos el código de arriba a abajo.

spam_amount = 0

# Asignación de variables: aquí creamos una variable llamada spam_amount y le asignamos el valor de 0 usando =, que se llama operador de asignación.
#
# **Nota**: si ha programado en ciertos otros lenguajes (como Java o C ++), puede estar notando algunas cosas que Python no requiere que hagamos aquí:
#
# * no necesitamos "declarar" spam_amount antes de asignarle
# * no necesitamos decirle a Python a qué tipo de valor se referirá spam_amount. De hecho, incluso podemos reasignar spam_amount para referirnos a un tipo diferente de cosas como una cadena o un booleano.

print(spam_amount)

# **Llamadas de función**: _print_ es una función de Python que muestra el valor que se le pasa en la pantalla. Llamamos a las funciones poniendo paréntesis después de su nombre y poniendo las entradas (o argumentos) a la función en esos paréntesis.

# Ordering Spam, egg, Spam, Spam, bacon and Spam (4 more servings of Spam)
spam_amount = spam_amount + 4

# La primera línea de arriba es un **comentario**. En Python, los comentarios comienzan con el símbolo _#_.
#
# A continuación vemos un ejemplo de reasignación. La reasignación del valor de una variable existente tiene el mismo aspecto que la creación de una variable: todavía utiliza el operador de asignación _=_.
#
# En este caso, el valor que estamos asignando a _spam_amount_ implica una aritmética simple en su valor anterior. Cuando encuentra esta línea, Python evalúa la expresión en el lado derecho de _=_ (0 + 4 = 4), y luego asigna ese valor a la variable en el lado izquierdo.

# +
if spam_amount > 0:
    print("But I don't want ANY spam!")

viking_song = "Spam Spam Spam"
print(viking_song)
# -

# No hablaremos mucho sobre "condicionales" hasta más tarde, pero, incluso si nunca ha codificado antes, probablemente pueda adivinar lo que hace. Python es apreciado por su legibilidad y simplicidad.
#
# Observe cómo indicamos qué código pertenece al _if. "¡Pero no quiero NINGÚN spam!"_ solo se supone que se imprime si _spam_amount_ es positivo. Pero el código posterior (como _print (viking_song)_) debe ejecutarse sin importar qué. ¿Cómo lo sabemos (y Python)?
#
# Los dos puntos (:) al final de la línea if indican que se está iniciando un nuevo "bloque de código". Las líneas posteriores que están sangradas son parte de ese bloque de código. Algunos otros idiomas usan {llaves "para marcar el comienzo y el final de los bloques de código. El uso de espacios en blanco significativos por Python puede ser sorprendente para los programadores que están acostumbrados a otros lenguajes, pero en la práctica puede conducir a un código más coherente y legible que los lenguajes que no imponen sangría de bloques de código.
#
# Las líneas posteriores que tratan con _viking_song_ no están sangradas con 4 espacios adicionales, por lo que no forman parte del bloque de código if. Veremos más ejemplos de bloques de código sangrados más adelante cuando definamos funciones y usemos bucles.
#
# Este fragmento de código también es nuestro primer avistamiento de una cadena **string** en Python:

"But I don't want ANY spam!"

# Las cadenas se pueden marcar con comillas dobles o simples. (Pero debido a que esta cadena en particular contiene un carácter de comillas simples, podríamos confundir a Python tratando de rodearla con comillas simples, a menos que tengamos cuidado).

viking_song = "Spam " * spam_amount
print(viking_song)

# El operador _\*_ se puede usar para multiplicar dos números (3 * 3 se evalúa como 9), pero de manera bastante divertida, también podemos multiplicar una cadena por un número, para obtener una versión que se ha repetido tantas veces. Python ofrece una serie de trucos descarados y pequeños que ahorran tiempo como este, donde los operadores como * y + tienen un significado diferente según el tipo de cosas a las que se aplican. (El término técnico para esto es [operador de sobrecarga](https://en.wikipedia.org/wiki/Operator_overloading))

# ## Números y aritmética en Python
# Ya hemos visto un ejemplo de una variable que contiene un número arriba:

spam_amount = 0

# "Número" es un buen nombre informal para el tipo de cosas, pero si quisiéramos ser más técnicos, podríamos preguntarle a Python cómo describiría el tipo de cosas que es *spam_amount*:

type(spam_amount)

# Es un *int* - abreviatura de entero. Hay otro tipo de número que comúnmente encontramos en Python:

type(19.95)

# Un *float* es un número con un lugar decimal, muy útil para representar cosas como pesos o proporciones.
#
# *type()* es la segunda función incorporada que hemos visto (después de *print()*), y es otra buena para recordar. Es muy útil poder preguntarle a Python "¿qué clase de cosa es esta?".
#
# Una cosa natural que desea hacer con los números es realizar operaciones aritméticas. Hemos visto el operador + para la suma y el operador * para la multiplicación (de una especie). Python también nos tiene cubiertos para el resto de los botones básicos en su calculadora:

print(5 / 2)
print(6 / 2)

# Siempre nos da un número decimal.
#
# El operador // nos da un resultado que se redondea al siguiente número entero.

print(5 // 2)
print(6 // 2)

# ### Order of operations
# The arithmetic we learned in primary school has conventions about the order in which operations are evaluated. Some remember these by a mnemonic such as **PEMDAS - Parentheses, Exponents, Multiplication/Division, Addition/Subtraction**.
#
# Python follows similar rules about which calculations to perform first. They're mostly pretty intuitive.

# In case it's helpful, here is the table of available arithmatic operations:

#
# | Operator     | Name           | Description                                            |
# |--------------|----------------|--------------------------------------------------------|
# | ``a + b``    | Addition       | Sum of ``a`` and ``b``                                 |
# | ``a - b``    | Subtraction    | Difference of ``a`` and ``b``                          |
# | ``a * b``    | Multiplication | Product of ``a`` and ``b``                             |
# | ``a / b``    | True division  | Quotient of ``a`` and ``b``                            |
# | ``a // b``   | Floor division | Quotient of ``a`` and ``b``, removing fractional parts |
# | ``a % b``    | Modulus        | Integer remainder after division of ``a`` by ``b``     |
# | ``a ** b``   | Exponentiation | ``a`` raised to the power of ``b``                     |
# | ``-a``       | Negation       | The negative of ``a``                                  |
#
# <span style="display:none"></span>

8 - 3 + 2

-3 + 4 * 2

# A veces, el orden predeterminado de las operaciones no es lo que queremos:

hat_height_cm = 25
my_height_cm = 190
# How tall am I, in meters, when wearing my hat?
total_height_meters = hat_height_cm + my_height_cm / 100
print("Height in meters =", total_height_meters, "?")

# Parentheses are your useful here. You can add them to force Python to evaluate sub-expressions in whatever order you want.

total_height_meters = (hat_height_cm + my_height_cm) / 100
print("Height in meters =", total_height_meters)

# ### Funciones incorporadas para trabajar con números
# min y max devuelven el mínimo y el máximo de sus argumentos, respectivamente ...

print(min(1, 2, 3))
print(max(1, 2, 3))

# *abs* returns the absolute value of it argument:

print(abs(32))
print(abs(-32))

# In addition to being the names of Python's two main numerical types, *int* and *float* can also be called as functions which convert their arguments to the corresponding type:

print(float(10))
print(int(3.33))
# They can even be called on strings!
print(int('807') + 1)

StarcoderdataJupyterScriptsDedupFiltered