Este es un tutorial básico de Python, un lenguaje interpretado orientado a objetos, que comparte algunas características de los lenguajes de programación Java y Schema. El objetivo es entender las bases del lenguaje, su construcción sintáctica utilizando algunos ejemplos pequeños.
Instalación de Python y Anaconda
Para instalar Python, podemos hacerlo de manera individual o a través del entorno de desarrollo para Data Science Anaconda, el cual incluye Python 3.8 y que permite crear diferentes entornos virtuales cada uno con sus versiones propias para Python y sus dependencias, así como librerías. Lo que permite evitar conflictos entre la versión de Python del sistema operativo y versiones requeridas para diversos proyectos.
Al ingresar al sitio con la siguiente liga: https://www.anaconda.com/products/individual podemos descargar Anaconda para la plataforma que utilizamos: Windows, Mac o Linux.
Una vez descargado el instalador, únicamente lo ejecutamos y la instalación se inicia sin ningún problema hasta concluir el proceso. Si requerimos algún tipo de información adicional en relación a los requerimientos mínimos del sistema o sobre el proceso, la documentación de la instalación se encuentra en la siguiente liga: Documentación Instalación Anaconda.
Una vez instalado, podemos usar el interprete de comando de anaconda para probar los ejemplos y la ejecución del código. Para abrir el interprete de comandos, en la barra de búsqueda escribimos Anaconda y en las opciones que aparecen seleccionamos: “Anaconda Prompt (Ananconda3).
Al seleccionarlo nos abre la ventana del interprete de comandos de Anaconda
Invocando el interprete de comandos de Python
Para invocar al interprete de comandos de python en la ventana del Prompt de Anaconda, únicamente ejecutamos python
Python se puede ejecutar interactivamente desde el interprete de comandos o también se puede invocar desde la línea de comandos para ejecutar un script. Primero veremos algunos ejemplos desde el interprete.
Al ejecutar el comando python en la línea de comandos, estamos invocando al interprete y este responde mostrando la versión de python, la fecha y hora de liberación de la versión, así como información adicional y del equipo en el que estamos, finalizando con los símbolos >>> donde podemos ejecutar ahora código de python.
Operadores
El interprete de python se puede utilizar para evaluar expresiones, por ejemplo, expresiones aritméticas simples. Si escribimos alguna expresión en el prompt >>> será evaluado y el resultado se mostrará en la siguiente línea:
>>> 1 + 1
2
>>> 2 * 3
6
Los operadores booleanos en python permiten evaluar los valores primitivos True Y False
>>> 1 == 0
False
>>> not (1 == 0)
True
>>> (2 == 2) and (2 == 3)
False
>>> (2 == 2) or (2 == 3)
True
Strings
Python maneja un tipo string similar a como se utiliza en Java en donde el poerador + es utilizado para concatenar valores de tipo string
>>> 'inteligencia' + "artificial"
'inteligenciaartificial'
El objeto string contiene métodos que permiten manipular las cadenas de caracteres
>>> 'artificial'.upper()
'ARTIFICIAL'
>>> 'Ayuda'.lower()
'ayuda'
>>> len('Ayuda')
5
Para encerrar cadenas podemos utilizar comillas simples ‘ ‘ o comillas dobles ” “, lo que permite anidar cadenas. También es posible almacenar expresiones en cadenas o strings
>>> s = 'hello world'
>>> print(s)
hello world
>>> s.upper()
'HELLO WORLD'
>>> len(s.upper())
11
>>> num = 8.0
>>> num += 2.5
>>> print(num)
10.5
En Python no se necesita declarar variables antes de asignarles un valor. En el ejemplo anterior vemos el uso de las variables s Y num, las cuales no se declararon previamente.
Para saber que otros métodos ofrece python para el manejo de strings y en general para cualquier tipo de dato utilizamos los comandos dir Y help.
>>> s = 'abc'
>>> dir(s)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__str__', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> help(s.find)
Help on built-in function find:
find(...) method of builtins.str instance
S.find(sub[, start[, end]]) -> int
Return the lowest index in S where substring sub is found,
such that sub is contained within S[start:end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
>>> s.find('b')
1
En el código anterior, con el comando dir obtenemos la lista de métodos disponibles para la variable s, la cual es un string. Con el comando help obtenemos la ayuda para el método find (buscar). Dado que la variable s contienen la cadena ‘abc’, al ejecutar s.find(‘b’) obtenemos que el caracter b se encuentra en la posición 1.
Estructura de datos
Python contiene algunas estructuras de datos ya predefinidas en el lenguaje
List
Las listas tipo List contienen una secuencia de elementos mutables (que pueden ser modificados):
>>> fruits = ['apple', 'orange', 'pear', 'banana']
>>> fruits[0]
'apple'
Podemos utilizar el operador + para realizar una concatenación de listas
>>> otherFruits = ['kiwi', 'strawberry']
>>> fruits + otherFruits
>>> ['apple', 'orange', 'pear', 'banana', 'kiwi', 'strawberry']
A diferencia de otros lenguajes, Python permite la indexación negativa para seleccionar desde el final de la lista. Para el ejemplo anterior fruits[-1] accede o hace referencia al último elemento de la lista, en este caso ‘banana’
>>> fruits[-2]
'pear'
>>> fruits.pop()
'banana'
>>> fruits
['apple', 'orange', 'pear']
>>> fruits.append('grapefruit')
>>> fruits
['apple', 'orange', 'pear', 'grapefruit']
>>> fruits[-1] = 'pineapple'
>>> fruits
['apple', 'orange', 'pear', 'pineapple']
En este ejemplo, el índice -2 hace referencia al penúltimo elemento de la lista, es decir, con -1 se accede al último y -2 al que sigue después del último y así sucesivamente. El método pop() devuelve al último elemento de la lista.
También podemos indexar múltiples elementos adyacentes utilizando el operador slice ( : ) , por ejemplo, fruits[1:3], retorna una lista de elementos en la posición 1 y 2. En general fruits[start:stop] devuelve los elementos que van desde start hasta stop-1 (stop menos uno).
También podemos utilizar fruits[start:] que retorna todos los elementos desde la posición de start hasta el final de la lista. Con la opción fruits[:end] obtenemos todos los elementos antes de la posición de end
>>> fruits[0:2]
['apple', 'orange']
>>> fruits[:3]
['apple', 'orange', 'pear']
>>> fruits[2:]
['pear', 'pineapple']
>>> len(fruits)
4
Los elementos almacenados dentro de una lista, pueden ser de cualquier tipo de dato soportado por Python, por lo que también podemos tener listas de listas
>>> lstOfLsts = [['a', 'b', 'c'], [1, 2, 3], ['one', 'two', 'three']]
>>> lstOfLsts[1][2]
3
>>> lstOfLsts[0].pop()
'c'
>>> lstOfLsts
[['a', 'b'], [1, 2, 3], ['one', 'two', 'three']]
Para saber que otros métodos podemos utilizar con listas, obtenemos la lista de métodos con dir y para saber como utilizar algún método con el comando help
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__delslice__', '__doc__', '__eq__', '__ge__', '__getattribute__',
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__',
'__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__',
'__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__',
'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse',
'sort']
>>> help(list.reverse)
Help on built-in function reverse:
reverse(...)
L.reverse() -- reverse \*IN PLACE\*
>>> lst = ['a', 'b', 'c']
>>> lst.reverse()
>>> ['c', 'b', 'a']`
Tuplas
Las tuplas son una estructura de datos similares a las listas pero en donde los elementos son inmutables, es decir, que no se pueden cambiar los elementos una vez creada la tupla y en lugar de usar corchetes, utilizamos paréntesis para definirlas.
>>> pair = (3, 5)
>>> pair[0]
3
>>> x, y = pair
>>> x
3
>>> y
5
>>> pair[1] = 6
TypeError: object does not support item assignment
Al querer modificar una tupla se lanza una excepción.
Sets
Los Sets o conjuntos son una estructura de datos que funcionan como una lista no ordenada sin duplicados. Para crear un set a partir de una lista utilizamos la instrucción set.
>>> shapes = ['circle', 'square', 'triangle', 'circle']
>>> setOfShapes = set(shapes)
Otra forma de crear un set es utilizando llaves o corchetes curvos:
>>> setOfShapes = {‘circle’, ‘square’, ‘triangle’, ‘circle’}
En el siguiente ejemplo se muestra como agregar elementos a un Set, probar si algún elemento se encuentra en el Set y realizar las operaciones comunes como la diferencia, la intersección y la unión.
>>> setOfShapes
set(['circle', 'square', 'triangle'])
>>> setOfShapes.add('polygon')
>>> setOfShapes
set(['circle', 'square', 'triangle', 'polygon'])
>>> 'circle' in setOfShapes
True
>>> 'rhombus' in setOfShapes
False
>>> favoriteShapes = ['circle', 'triangle', 'hexagon']
>>> setOfFavoriteShapes = set(favoriteShapes)
>>> setOfShapes - setOfFavoriteShapes
set(['square', 'polygon'])
>>> setOfShapes & setOfFavoriteShapes
set(['circle', 'triangle'])
>>> setOfShapes | setOfFavoriteShapes
set(['circle', 'square', 'triangle', 'polygon', 'hexagon'])
El orden en el que se imprimen los Set puede variar de acuerdo al equipo en el que se ejecuta dado que el Set es una colección no ordenada.
Diccionarios
El último tipo de estructura de dato construido en Python es el Diccionario, el cual almacena un mapeo entre un tipo de objeto (la llave o key) y otro (el valor). La llave debe ser de un tipo inmutable (string, number o tuple) y el valor puede ser cualquier tipo de dato python.
El diccionario es una tabla hash para la cual no existe un orden fijo de las llaves, por lo tanto, la impresión del objeto no siempre devuelve el mismo orden. Se pueden también crear diccionarios de diccionarios.
>>> studentIds = {'knuth': 42.0, 'turing': 56.0, 'nash': 92.0}
>>> studentIds['turing']
56.0
>>> studentIds['nash'] = 'ninety-two'
>>> studentIds
{'knuth': 42.0, 'turing': 56.0, 'nash': 'ninety-two'}
>>> del studentIds['knuth']
>>> studentIds
{'turing': 56.0, 'nash': 'ninety-two'}
>>> studentIds['knuth'] = [42.0, 'forty-two']
>>> studentIds
{'knuth': [42.0, 'forty-two'], 'turing': 56.0, 'nash': 'ninety-two'}
>>> studentIds.keys()
['knuth', 'turing', 'nash']
>>> studentIds.values()
[[42.0, 'forty-two'], 56.0, 'ninety-two']
>>> studentIds.items()
[('knuth', [42.0, 'forty-two']), ('turing',56.0), ('nash', 'ninety-two')]
>>> len(studentIds)
3
Se pueden utilizar los comandos dir y help para obtener información sobre los métodos incorporados para los diccionarios.
Scripts de Python
Una vez que ya hemos visto el uso del interprete de comandos python, ahora trabajaremos con los scripts. para salir del interprete de comandos con python ejecutamos quit()
Para el primer ejemplo, creamos un archivo con el nombre foreach.py y escribimos el siguiente código donde utilizamos el ciclo for:
# Esto es un comentario
fruits = ['apples', 'oranges', 'pears', 'bananas']
for fruit in fruits:
print(fruit + ' en venta')
fruitPrices = {'apples': 2.00, 'oranges': 1.50, 'pears': 1.75}
for fruit, price in fruitPrices.items():
if price < 2.00:
print('%s precio %f por kilo' % (fruit, price))
else:
print(fruit + ' es demasiado cara!')
Guardamos el archivo en la carpeta donde nos encontramos en la ventana de la línea de comandos y ejecutamos el script con la isntrucción: python foreach.py
(base) C:\Users\PC>python foreach.py
apples en venta
oranges en venta
pears en venta
bananas en venta
apples es demasiado cara!
oranges precio 1.500000 por kilo
pears precio 1.750000 por kilo
La impresión de las sentencias anteriores puede cambiar de orden dado que estamos recorriendo las llaves de un diccionario, el cual mantiene un almacenamiento no ordenada, tipo hash. Otro punto importante es que en python no se utilizan las llaves o paréntesis curvos para delimitar un bloque de código, como el bloque que pertenece al ciclo for, por lo que Python utiliza la indentación, todo lo que se encuentra un tabulador adelante de la columna donde inicia el for, pertenece al ciclo for. En ese sentido, la siguiente línea donde se crea el diccionario de precios, ya no está indentada.
El siguiente script muestra el uso de for with if en la construcción de listas
nums = [1, 2, 3, 4, 5, 6]
plusOneNums = [x + 1 for x in nums]
oddNums = [x for x in nums if x % 2 == 1]
print(oddNums)
oddNumsPlusOne = [x + 1 for x in nums if x % 2 == 1]
print(oddNumsPlusOne)
La salida al ejecutar el código dentro de un archivo llamado listas.py es la siguiente
(base) C:\Users\PC>python listas.py
[1, 3, 5]
[2, 4, 6]
La recomendación es utilizar un editor de código como Spyder (Se encuentra dentro de Anaconda) o VS Code, entre otros, para escribir los scripts y de esa forma poder establecer correctamente los espacios, tabuladores para crear la indentación adecuada para Python.
Funciones
para definir funciones utilizamos la palabra def nombre_de_la_función(argumentos): delimitando con los dos puntos. Todo lo que va dentro de la función se delimita con el tabulador o la identación a la derecha.
fruitPrices = {'apples': 2.00, 'oranges': 1.50, 'pears': 1.75}
def buyFruit(fruit, numPounds):
if fruit not in fruitPrices:
print("Lo siento, no tenemos %s" % (fruit))
else:
cost = fruitPrices[fruit] * numPounds
print("Estos son %f por favor" % (cost))
# Main Function
if __name__ == '__main__':
buyFruit('apples', 2.4)
buyFruit('coconuts', 2)
En lugar de tener una función main como en otros lenguajes, la expresión booleana if __name__ == ‘__main__’ se utiliza para delimitar expresiones que se ejecutan cuando se invoca el archivo como script en la línea de comandos. El código después de esta expresión es el equivalente a lo que se colocaría dentro de la función main en otros lenguajes.
El código anterior lo guardamos como frutas.py y lo invocamos:
(base) C:\Users\PC>python frutas.py
Estos son 4.800000 por favor
Lo siento, no tenemos coconuts
Clases
El siguiente ejemplo define la clase FruitShop
class FruitShop:
def __init__(self, name, fruitPrices):
"""
name: Name of the fruit shop
fruitPrices: Dictionary with keys as fruit
strings and prices for values e.g.
{'apples': 2.00, 'oranges': 1.50, 'pears': 1.75}
"""
self.fruitPrices = fruitPrices
self.name = name
print('Welcome to %s fruit shop' % (name))
def getCostPerPound(self, fruit):
"""
fruit: Fruit string
Returns cost of 'fruit', assuming 'fruit'
is in our inventory or None otherwise
"""
if fruit not in self.fruitPrices:
return None
return self.fruitPrices[fruit]
def getPriceOfOrder(self, orderList):
"""
orderList: List of (fruit, numPounds) tuples
Returns cost of orderList, only including the values of
fruits that this fruit shop has.
"""
totalCost = 0.0
for fruit, numPounds in orderList:
costPerPound = self.getCostPerPound(fruit)
if costPerPound != None:
totalCost += numPounds * costPerPound
return totalCost
def getName(self):
return self.name
La clase FruitShop tiene dos atributos: el nombre de la tienda (name) y el precio de algunas frutas (fruitPrices) y define algunas funciones o métodos para trabajar con esos datos. La principal ventaja de las clases es que encapsulan los datos para evitar su uso inapropiado. La abstracción que provee el uso de la clase a través de los objetos facilita la creación de código de propósito general.
Creación de objetos de la clase
Si guardamos el código anterior en un archivo llamado shop.py. En un nuevo archivo dentro de la misma carpeta importamos el archivo utilizando import shop sin agregar la extensión, creamos un objeto de la clase FruitShop con: shop.FruitShop(nombre, precios)
Nota: (No se usa new como en otros lenguajes)
import shop
shopName = 'the Berkeley Bowl'
fruitPrices = {'apples': 1.00, 'oranges': 1.50, 'pears': 1.75}
berkeleyShop = shop.FruitShop(shopName, fruitPrices)
applePrice = berkeleyShop.getCostPerPound('apples')
print(applePrice)
print('Apples cost $%.2f at %s.' % (applePrice, shopName))
otherName = 'the Stanford Mall'
otherFruitPrices = {'kiwis': 6.00, 'apples': 4.50, 'peaches': 8.75}
otherFruitShop = shop.FruitShop(otherName, otherFruitPrices)
otherPrice = otherFruitShop.getCostPerPound('apples')
print(otherPrice)
print('Apples cost $%.2f at %s.' % (otherPrice, otherName))
print("My, that's expensive!")
Guardamos este archivo con el nombre shopTest.py y lo ejecutamos de la siguiente manera:
(base) C:\Users\PC>python shopTest.py
Welcome to the Berkeley Bowl fruit shop
1.0
Apples cost $1.00 at the Berkeley Bowl.
Welcome to the Stanford Mall fruit shop
4.5
Apples cost $4.50 at the Stanford Mall.
My, that's expensive!
La sentencia import shop le indica a python que cargue todas las funciones y clases del archivo shop.py. La línea berkeleyShop = shop.FruitShop(shopName, fruitPrices) crea una instancia invocando el constructor de la clase FruitShop el cual se definió en la función __init__. Esta función constructor declara 3 argumentos (self, name, fruitPrices), pero al invocarla sólo se envían 2. Todos los métodos en una clase tienen el argumento self como primer argumento. El valor de esta variable se especifica de manera automática como el mismo objeto. Cuando se invoca un método, sólo se envían los argumentos restantes. El argumento self contiene todos los datos de la clase, en este caso name y fruitPrices para la instancia en cuestión (Es el equivalente de this en java).
Variables estáticas y de instancia
Para describir el uso de las variables estáticas y de instancia, creamos el archivo person_class.py con lo siguiente:
class Person:
population = 0
def __init__(self, myAge):
self.age = myAge
Person.population += 1
def get_population(self):
return Person.population
def get_age(self):
return self.age
Al compilar y ejecutar el script con el intérprete de comandos Python:
>>> import person_class
>>> p1 = person_class.Person(12)
>>> p1.get_population()
1
>>> p2 = person_class.Person(63)
>>> p1.get_population()
2
>>> p2.get_population()
2
>>> p1.get_age()
12
>>> p2.get_age()
63
La variable age es una variable de instancia y population es una variable estática. El valor de la variable population se comparte con todas las instancias de la clase Person donde cada instancia tiene su propia variable age.