<jupyter_start><jupyter_text>Arrays of objectsA very powerful feature is that we can save instances of classes in an array. This gives us great functionality if we want to save objects for later retrieval using the **numpy.save()** and **numpy.load()** functions.Python allows object serialisation using cPickle, but serialising with numpy is easier, since we don't have to create file objects beforehand. Performance can be similar, although numpy is slightly faster.<jupyter_code># Import libs and mods
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Observe the following "Account" class
class Cuenta(object):   
    def __init__(self, nombre, saldo_inicial):
        self._nombre = nombre
        self._saldo = saldo_inicial
        self._operaciones = []
    
    def ingresar(self, cantidad):
        self._saldo += cantidad
        self._operaciones.append("Ingreso de " + str(cantidad)+"\nSaldo en cuenta de " + str(self._saldo))
    
    def retirar(self, cantidad):
        if cantidad > self._saldo:
            print ("Operación denegada por la entidad")
            print ("Saldo insuficiente")
            self._operaciones.append("Operación de retirada cancelada, saldo insuficiente")
        else:
            self._operaciones.append("_"*25 + "\nRetirada de " + str(cantidad)+ "\nSaldo en cuenta de " + str(self._saldo))
            self._saldo -= cantidad
        
    def consulta_saldo(self):
        print ("Tu saldo en cuenta es de: " + str(self._saldo))
        
    def consulta_operaciones(self, ultimas = 10):
        if len(self._operaciones)<ultimas:
            ultimas = len(self._operaciones)
        for n in range(ultimas -1, -1, -1):
            print (self._operaciones[n])
# Create 50 random accounts with an initial balance of 2500 euros. 
# For each of them, perform 25 random operations of withdrawal or deposit of amounts from 0 to 200 euros.
# Create random names for the account holders 
# Use the files "data/50_nombres.txt" and "data/50_ape.txt".
nombres = np.loadtxt("data/50_nombres.txt", dtype="str")
apellidos = np.loadtxt("data/50_ape.txt", dtype="str")

cuentas = []
for n in range(50):
        # We create a random name for the account holder.
        nombre = np.random.choice(nombres).title()
        ape1 = np.random.choice(apellidos).title()
        ape2 = np.random.choice(apellidos).title()
        titular = " ".join((nombre, ape1, ape2))
        # We create an account
        cuenta = Cuenta(titular, 2500)
        # Do 25 operations
        for n in range(25):
            cantidad = np.random.randint(200)
            tipo_op = np.random.choice(["R", "I"])
            if tipo_op == "R":
                cuenta.retirar(cantidad)
            else:
                cuenta.ingresar(cantidad)
        cuentas.append(cuenta)

# Save the list of accounts as an array in "data/accounts_allocations.npy" # Save the list of accounts as an array in "data/accounts_allocations.npy".
np.save("data/cuentas_aleatorias.npy", np.array(cuentas))
# Reads the accounts from the saved file
# Prints the owners of accounts 10 to 13 and their balances
cuentas = np.load("data/cuentas_aleatorias.npy")
for n in range(9, 13):
    print "Cuenta #{0}".format(n+1)
    print "Titular: " + cuentas[n]._nombre
    cuentas[n].consulta_saldo()
    print "_"*20
# Let's check the advantages of serialising objects with numpy versus normal serialisation.
import cPickle
import time

# Decorator function that will "time" how long it takes to execute a function
def cronometro(funcion):
    def wrapper(*args, **kwargs):
        # Tiempo de inicio de ejecución.
        inicio = time.time()
        # Ejecutamos la funcion
        ret = funcion(*args, **kwargs)
        # Tiempo de finalización de la ejecución.
        fin = time.time()
        print "La función se ha ejecutado en " + str(fin - inicio) + " segundos"
        return ret
    return wrapper

@cronometro
def guarda_objetos(lista_objetos, path):
    cPickle.dump(lista_objetos, open(path, "w"))

@cronometro
def guarda_objetos2(arr_objetos, path):
    np.save(path, arr_objetos)
    
@cronometro
def carga_objetos(path):
    return cPickle.load(open(path, "r"))

@cronometro
def carga_objetos2(path):
    return np.load(path)

nombres = np.loadtxt("data/50_nombres.txt", dtype = "|S15")
# Creamos una lista con 50000 cuentas con saldo inicial 1000 euros
lista_cuentas = [Cuenta(np.random.choice(nombres).title(), 1000) for n in range(50000)]
arr_cuentas = np.array(lista_cuentas)

guarda_objetos(lista_cuentas, "data/lista_cuentas.dat")
guarda_objetos2(arr_cuentas, "data/arr_cuentas.npy")

res = carga_objetos("data/lista_cuentas.dat")
res = carga_objetos2("data/arr_cuentas.npy")<jupyter_output>La función se ha ejecutado en 1.16118097305 segundos
La función se ha ejecutado en 0.55837893486 segundos
La función se ha ejecutado en 0.89496588707 segundos
La función se ha ejecutado en 0.581037044525 segundos
{'fraction_non_alphanumeric': 0.10107570529734118, 'fraction_numerical': 0.026385224274406333, 'mean_word_length': 3.288946910356832, 'pattern_counts': {'":': 1, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '341290', 'license': 'MIT', 'n_tokens_mistral': 1731, 'n_tokens_neox': 1638, 'n_words': 479, 'path': 'python-engineering/04_Objects_Arrays.ipynb', 'repo_name': 'manuparra/python-courses', 'size': '4927'}