2 * 4 - (7 - 1) / 3 + 1.0

"""
Explanation: Introducción a la sintaxis de Python
En esta clase haremos una rápida introducción a la sintaxis de Python. Veremos cuáles son los tipos y estructuras básicas de este lenguaje. Seguro que ya has oído hablar mucho sobre las bondades de Python frente a otros lenguajes. Si no es así, échale un vistazo a esto.
¿Estás preparado? ¡Pues Empezamos!
Tipos numéricos
Python dispone de los tipos numéricos y las operaciones más habituales:
End of explanation
"""


1 / 0 

1.0 / 0.0

"""
Explanation: Las divisiones por cero lanzan un error:
End of explanation
"""


3 / 2

"""
Explanation: <div class="alert alert-info">Más adelante veremos cómo tratar estos errores. Por otro lado, cuando usemos NumPy esta operación devolverá `NaN`.</div>

La división entre enteros en Python 3 devuelve un número real, al contrario que en Python 2.
End of explanation
"""


3 // 2

"""
Explanation: Se puede forzar que la división sea entera con el operador //:
End of explanation
"""


2 ** 16

"""
Explanation: Se puede elevar un número a otro con el operador **:
End of explanation
"""


2 + 3j

1j

# Valor absoluto
abs(2 + 3j)

"""
Explanation: Otro tipo que nos resultará muy útil son los complejos:
End of explanation
"""


abs(_13)

"""
Explanation: <div class="alert alert-info"><strong>Tip de IPython</strong>: podemos recuperar resultados pasados usando `_<n>`. Por ejemplo, para recuperar el resultado correspondiente a `Out [7]`, usaríamos `_7`. Esta variable guarda ese valor para toda la sesión.</div>
End of explanation
"""


int(18.6)

round(18.6)

float(1)

complex(2)

str(256568)

"""
Explanation: Podemos convertir variables a int, float, complex, str...
End of explanation
"""


a = 2.
type(a)

isinstance(a, float)

"""
Explanation: Podemos comprobar el tipo de una variable:
End of explanation
"""


print('hola mundo')

max(1,5,8,7)

min(-1,1,0)

"""
Explanation: Otras funciones útiles son:
End of explanation
"""


a = 1 + 2j

"""
Explanation: ¡Acabas de utilizar funciones! Como ves es una manera bastante estándar: los argumentos se encierran entre paréntesis y se separan por comas. Se hace de esta manera en otros lenguajes de programación y no requiere mayor explicación, de momento.
<div class="alert alert-warning">La <strong>función <code>print</code></strong> es la que se usa para imprimir resultados por pantalla. Por si lo ves en algún sitio, en Python 2 era una sentencia y funcionaba de manera distinta, sin paréntesis y sin posibilidad de pasar argumentos adicionales.</div>

Asignación y operadores de comparación
La asignación se realiza con el operador =. Los nombres de las variables en Python pueden contener caracteres alfanuméricos (empezando con una letra) a-z, A-Z, 0-9 y otros símbolos como la _. 
Por cuestiones de estilo, las variables suelen empezar con minúscula, reservando la mayúcula para clases. 
Algunos nombres no pueden ser usados porque son usados por python:
and, as, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try, while, with, yield
End of explanation
"""


b = 3.14159
b

"""
Explanation: En Python la asignación no imprime el resultado por pantalla, al contrario de como sucede en MATLAB y Octave (salvo que se incluya el punto y coma al final). La mejor manera de visualizar la variable que acabamos de asignar es esta:
End of explanation
"""


x, y = 1, 2
x, y

"""
Explanation: En una celda podemos escribir código que ocupe varias líneas. Si la última de ellas devuelve un resultado, este se imprimirá.
End of explanation
"""


x, y = y, x
x, y

"""
Explanation: <div class="alert alert-info">Podemos realizar **asignación múltiple**, que hemos hecho en la celda anterior con las variables `x` e `y` para intercambiar valores de manera intuitiva:</div>
End of explanation
"""


x == y

print(x != y)

print(x < y)
print(x <= y)
print(x > y)
print(x >= y)

# incluso:
x = 5.
6. < x < 8.

"""
Explanation: Los operadores de comparación son:

== igual a
!= distinto de 
&lt; menor que
&lt;= menor o igual que

Devolverán un booleano: True o False
End of explanation
"""


1 + 1j < 0 + 1j

# En las cadenas de texto sí existe un orden
'aaab' > 'ba'

"""
Explanation: Si la ordenación no tiene sentido nos devolverá un error:
End of explanation
"""


True and False

not False

True or False

# Una curiosidad:
(True + True) * 10 

"""
Explanation: Booleanos
End of explanation
"""


una_lista = [1, 2, 3.0, 4 + 0j, "5"]
una_tupla = (1, 2, 3.0, 4 + 0j, "5")
print(una_lista)
print(una_tupla)
print(una_lista == una_tupla)

"""
Explanation: Otros tipos de datos
Otro tipo de datos muy importante que vamos a usar son las secuencias: las tuplas y las listas. Ambos son conjuntos ordenados de elementos: las tuplas se demarcan con paréntesis y las listas con corchetes.
End of explanation
"""


tupla_sin_parentesis = 2,5,6,9,7
type(tupla_sin_parentesis)

"""
Explanation: Para las tuplas, podemos incluso obviar los paréntesis:
End of explanation
"""


2 in una_lista

2 in una_tupla

"""
Explanation: En los dos tipos podemos:

Comprobar si un elemento está en la secuencia con el operador in:
End of explanation
"""


len(una_lista)

"""
Explanation: Saber cuandos elementos tienen con la función len:
End of explanation
"""


print(una_lista[0])  # Primer elemento, 1
print(una_tupla[1])  # Segundo elemento, 2
print(una_lista[0:2])  # Desde el primero hasta el tercero, excluyendo este: 1, 2
print(una_tupla[:3])  # Desde el primero hasta el cuarto, excluyendo este: 1, 2, 3.0
print(una_lista[-1])  # El último: 4 + 0j
print(una_tupla[:])  # Desde el primero hasta el último
print(una_lista[::2])  # Desde el primero hasta el último, saltando 2: 1, 3.0

"""
Explanation: Podemos indexar las secuencias, utilizando la sintaxis [&lt;inicio&gt;:&lt;final&gt;:&lt;salto&gt;]:
End of explanation
"""


mis_asignaturas = [
['Álgebra', 'Cálculo', 'Física'],
['Mecánica', 'Termodinámica'],
['Sólidos', 'Electrónica']
]
mis_asignaturas

"""
Explanation: Veremos más cosas acerca de indexación en NumPy, así que de momento no te preocupes. Sólo recuerda una cosa:
¡En Python, la indexación empieza por CERO!
Podemos complicarlo un poco más y hacer cosas como una lista de listas:
End of explanation
"""


print(x,y)
if x > y:
    print("x es mayor que y")
    print("x sigue siendo mayor que y")

if 1 < 0:
    print("1 es menor que 0")
print("1 sigue siendo menor que 0")  # <-- ¡Mal!

if 1 < 0:
    print("1 es menor que 0")
     print("1 sigue siendo menor que 0")

"""
Explanation: Esto nos será de gran ayuda en el futuro para construir arrays.
Estructuras de control (I): Condicionales
if &lt;condition&gt;:
    &lt;do something&gt;
elif &lt;condition&gt;:
    &lt;do other thing&gt;
else:
    &lt;do other thing&gt;

<div class="alert alert-error"><strong>Importante:</strong> En Python los bloques se delimitan por sangrado, utilizando siempre cuatro espacios. Cuando ponemos los dos puntos al final de la primera línea del condicional, todo lo que vaya a continuación con *un* nivel de sangrado superior se considera dentro del condicional. En cuanto escribimos la primera línea con un nivel de sangrado inferior, hemos cerrado el condicional. Si no seguimos esto a rajatabla Python nos dará errores; es una forma de forzar a que el código sea legible.</div>
End of explanation
"""


print(x,y)
if x > y:
    print("x es mayor que y")
else:
    print("x es menor que y")

print(x, y)
if x < y:
    print("x es menor que y")
elif x == y:
    print("x es igual a y")
else:
    print("x no es ni menor ni igual que y")

"""
Explanation: Si queremos añadir ramas adicionales al condicional, podemos emplear la sentencia elif (abreviatura de else if). Para la parte final, que debe ejecutarse si ninguna de las condiciones anteriores se ha cumplido, usamos la sentencia else:
End of explanation
"""


ii = -2
while ii < 5:
    print(ii)
    ii += 1

"""
Explanation: Estructuras de control (II): Bucles
En Python existen dos tipos de estructuras de control típicas:

Bucles while
Bucles for

while
Los bucles while repetiran las sentencias anidadas en él mientras se cumpla una condición:
while &lt;condition&gt;:
    &lt;things to do&gt;

Como en el caso de los condicionales, los bloques se separan por indentación sin necesidad de sentencias del tipo end
End of explanation
"""


ii = 0
while ii < 5:
    print(ii)
    ii += 1
    if ii == 3:
        break

"""
Explanation: <div class="alert alert-info"><strong>Tip</strong>: 
`ii += 1` equivale a `ii = ii + 1`. En el segundo Python, realiza la operación ii + 1 creando un nuevo objeto con ese valor y luego lo asigna a la variable ii; es decir, existe una reasignación. En el primero, sin embargo, el incremento se produce sobre la propia variable. Esto puede conducirnos a mejoras en velocidad.

Otros operadores 'in-place' son: `-=`, `*=`, `/=` 
</div>

Se puede interrumpir el bucle a la mitad con la sentencia break:
End of explanation
"""


ii = 0
while ii < 5:
    print(ii)
    ii += 1
    if ii == 3:
        break
else:
    print("El bucle ha terminado")

ii = 0
while ii < 5:
    print(ii)
    ii += 1
    #if ii == 3:
        #break
else:
    print("El bucle ha terminado")

"""
Explanation: Un bloque else justo después del bucle se ejecuta si este no ha sido interrumpido por nosotros:
End of explanation
"""


for ii in (1,2,3,4,5):
    print(ii)

for nombre in "Juan", "Luis", "Carlos":
    print(nombre)

for ii in range(3):
    print(ii)

for jj in range(2, 5):
    print(jj)

"""
Explanation: for
El otro bucle en Python es el bucle for, y funciona de manera un que puede resultar chocante al principio. La idea es recorrer un conjunto de elementos:
for &lt;element&gt; in &lt;iterable_object&gt;:
    &lt;do whatever...&gt;
End of explanation
"""


