# ALS Parcial 2b 2018/19 MIT License Baltasar <jbgarcia@uvigo.es>
"""
1. La clase Contacto guarda los datos: nombre, apellidos, tlf (teléfono), y email, utilizando propiedades para acceder a la información. Los métodos de la clase serán: __init__(), __str_() (que devuelve los datos en formato <apellidos>, <nombre> (<tlf>): <email>), y __getattr__(). El acceso a nombre_completo (que devuelve el nombre en el formato <apellidos>, <nombre>) se hará mediante __getattr__(), no existiendo otra propiedad, atributo o método que lo haga.
c1 = Contacto(“Baltasar”, “Garcia”, 988368891, “jbgarcia@uvigo.es”)
print(c1.nombre) # Baltasar
print(c1.nombre_completo) # García, Baltasar
2. Cree los métodos to_csv(f) y from_csv(f). El primero escribe la codificación CSV del objeto como un archivo, la segunda toma un archivo con contenido en formato CSV y crea un objeto con dicho contenido. Será necesario crear un lector r (csv.reader) sobre el archivo f y leer la fila CSV con next(r), mientras que para guardar datos se creará un escritor w (csv.writer) y se guardará la información con w.writerow(l). El orden de guardado de los atributos será el mismo que el utilizado para la construcción de los objetos Contacto.
c1 = Contacto(“Baltasar”, “Garcia”, 988368891, “jbgarcia@uvigo.es”)
with open(“datos.csv”, “wt”) as f:
c1.to_csv(f)
with open(“datos.csv”, “rt”) as f:
print(str(Contacto.from_csv(f))) # García, Baltasar (988368891): ...
3. Escriba la función lista_contactos(lc, f), que recibe como parámetros una lista de registros y una función que define cómo combinar dos contactos. Deben utilizarse exclusivamente lambdas, y para esta función en particular, reducir la lista.
listado = lista_contactos([c1, c2, c3], lambda c1, c2: str(c1) + “\n ” + str(c2))
print(listado) # Baltasar…
"""
import csv
class Contacto:
def __init__ ( self , nombre, apellidos, tlf, email ) :
self ._nombre = nombre
self ._apellidos = apellidos
self ._tlf = tlf
self ._email = email
@ property
def nombre( self ) :
return self ._nombre
@ property
def apellidos( self ) :
return self ._apellidos
@ property
def tlf( self ) :
return self ._tlf
@ property
def email ( self ) :
return self ._email
@ staticmethod
def from_csv( f) :
reader = csv .reader ( f)
data = next( reader)
toret = Contacto( data[ 0 ] , data[ 1 ] , int ( data[ 2 ] ) , data[ 3 ] )
return toret
def to_csv( self , f) :
writer = csv .writer ( f)
writer.writerow ( [ self .nombre , self .apellidos , self .tlf , self .email ] )
def __getattr__ ( self , s) :
if s == "nombre_completo" :
return self .apellidos + ", " + self .nombre
else :
raise AttributeError ( s)
def __str__ ( self ) :
return str .format ( "{} ({}): {}" , self .nombre_completo , self .tlf , self .email )
lista_contactos = lambda l, f:(
"" if not l or l == [ ]
else f( l[ 0 ] , lista_contactos( l[ 1 :] , f) ) )
import unittest
import io
class TestContacto( unittest .TestCase ) :
def setUp( self ) :
self .c1 = Contacto( "Baltasar" , "García" , 988368891 , "jbgarcia@uvigo.es" )
self .todos_contactos = [ self .c1 ]
self .todos_resultados = [
"García, Baltasar (988368891): jbgarcia@uvigo.es" ,
]
def testContactoStr( self ) :
self .assertEqual ( len ( self .todos_resultados ) , len ( self .todos_contactos ) )
for i, resultado in enumerate ( self .todos_resultados ) :
resultado_contacto = TestContacto.prepara_resultado ( str ( self .todos_contactos [ i] ) )
resultado = TestContacto.prepara_resultado ( resultado)
self .assertEqual ( resultado, resultado_contacto)
def testContactoNombreCompleto( self ) :
for c in self .todos_contactos :
nombre_completo = c.apellidos + ", " + c.nombre
self .assertEqual ( nombre_completo, c.nombre_completo )
def testContactoCSV( self ) :
for c in self .todos_contactos :
with io.StringIO ( ) as s:
c.to_csv ( s)
self .assertEqual ( "," .join ( [ c.nombre , c.apellidos , str ( c.tlf ) , c.email ] ) , s.getvalue ( ) .strip ( ) )
def testLoadFromCSV( self ) :
for i, c1 in enumerate ( self .todos_contactos ) :
with io.StringIO ( "," .join ( [ c1.nombre , c1.apellidos , str ( c1.tlf ) , c1.email ] ) ) as f:
c2 = Contacto.from_csv ( f)
self .assertEqual ( c1.nombre , c2.nombre )
self .assertEqual ( c1.apellidos , c2.apellidos )
self .assertEqual ( c1.tlf , c2.tlf )
self .assertEqual ( c1.email , c2.email )
def testListaRegistros( self ) :
resultado = lista_contactos( self .todos_contactos , lambda x, y: str ( x) + "\n " + str ( y) ) .strip ( )
todos_resultados = "\n " .join ( [ str ( c) for c in self .todos_contactos ] )
self .assertEqual ( todos_resultados, resultado)
@ staticmethod
def prepara_resultado( s) :
return s.strip ( ) .replace ( '\' ' , '"' ) .replace ( ' ' , "" )
if __name__ == "__main__" :
unittest .main ( )
IyBBTFMgUGFyY2lhbCAyYiAyMDE4LzE5IE1JVCBMaWNlbnNlIEJhbHRhc2FyIDxqYmdhcmNpYUB1dmlnby5lcz4KCgoiIiIKICAgIDEuIExhIGNsYXNlIENvbnRhY3RvIGd1YXJkYSBsb3MgZGF0b3M6IG5vbWJyZSwgYXBlbGxpZG9zLCB0bGYgKHRlbMOpZm9ubyksIHkgZW1haWwsIHV0aWxpemFuZG8gcHJvcGllZGFkZXMgcGFyYSBhY2NlZGVyIGEgbGEgaW5mb3JtYWNpw7NuLiBMb3MgbcOpdG9kb3MgZGUgbGEgY2xhc2Ugc2Vyw6FuOiBfX2luaXRfXygpLCBfX3N0cl8oKSAocXVlIGRldnVlbHZlIGxvcyBkYXRvcyBlbiBmb3JtYXRvIDxhcGVsbGlkb3M+LCA8bm9tYnJlPiAoPHRsZj4pOiA8ZW1haWw+KSwgeSBfX2dldGF0dHJfXygpLiBFbCBhY2Nlc28gYSBub21icmVfY29tcGxldG8gKHF1ZSBkZXZ1ZWx2ZSBlbCBub21icmUgZW4gZWwgZm9ybWF0byA8YXBlbGxpZG9zPiwgPG5vbWJyZT4pIHNlIGhhcsOhIG1lZGlhbnRlIF9fZ2V0YXR0cl9fKCksIG5vIGV4aXN0aWVuZG8gb3RyYSBwcm9waWVkYWQsIGF0cmlidXRvIG8gbcOpdG9kbyBxdWUgbG8gaGFnYS4KCiAgICAJYzEgPSBDb250YWN0byjigJxCYWx0YXNhcuKAnSwg4oCcR2FyY2lh4oCdLCA5ODgzNjg4OTEsIOKAnGpiZ2FyY2lhQHV2aWdvLmVz4oCdKQoJcHJpbnQoYzEubm9tYnJlKQkJCQkJIyBCYWx0YXNhcgoJcHJpbnQoYzEubm9tYnJlX2NvbXBsZXRvKQkJCQkjIEdhcmPDrWEsIEJhbHRhc2FyCgoKICAgIDIuIENyZWUgbG9zIG3DqXRvZG9zIHRvX2NzdihmKSB5IGZyb21fY3N2KGYpLiBFbCBwcmltZXJvIGVzY3JpYmUgbGEgY29kaWZpY2FjacOzbiBDU1YgZGVsIG9iamV0byBjb21vIHVuIGFyY2hpdm8sIGxhIHNlZ3VuZGEgdG9tYSB1biBhcmNoaXZvIGNvbiBjb250ZW5pZG8gZW4gZm9ybWF0byBDU1YgeSBjcmVhIHVuIG9iamV0byBjb24gZGljaG8gY29udGVuaWRvLiBTZXLDoSBuZWNlc2FyaW8gY3JlYXIgdW4gbGVjdG9yIHIgKGNzdi5yZWFkZXIpIHNvYnJlIGVsIGFyY2hpdm8gZiB5IGxlZXIgbGEgZmlsYSBDU1YgY29uIG5leHQociksIG1pZW50cmFzIHF1ZSBwYXJhIGd1YXJkYXIgZGF0b3Mgc2UgY3JlYXLDoSB1biBlc2NyaXRvciB3IChjc3Yud3JpdGVyKSB5IHNlIGd1YXJkYXLDoSBsYSBpbmZvcm1hY2nDs24gY29uIHcud3JpdGVyb3cobCkuIEVsIG9yZGVuIGRlIGd1YXJkYWRvIGRlIGxvcyBhdHJpYnV0b3Mgc2Vyw6EgZWwgbWlzbW8gcXVlIGVsIHV0aWxpemFkbyBwYXJhIGxhIGNvbnN0cnVjY2nDs24gZGUgbG9zIG9iamV0b3MgQ29udGFjdG8uCiAgICAgICAKCWMxID0gQ29udGFjdG8o4oCcQmFsdGFzYXLigJ0sIOKAnEdhcmNpYeKAnSwgOTg4MzY4ODkxLCDigJxqYmdhcmNpYUB1dmlnby5lc+KAnSkKCgl3aXRoIG9wZW4o4oCcZGF0b3MuY3N24oCdLCDigJx3dOKAnSkgYXMgZjoKCQljMS50b19jc3YoZikKCgl3aXRoIG9wZW4o4oCcZGF0b3MuY3N24oCdLCDigJxydOKAnSkgYXMgZjoKCQlwcmludChzdHIoQ29udGFjdG8uZnJvbV9jc3YoZikpKQkJIyBHYXJjw61hLCBCYWx0YXNhciAoOTg4MzY4ODkxKTogLi4uCgoKICAgIDMuIEVzY3JpYmEgbGEgZnVuY2nDs24gbGlzdGFfY29udGFjdG9zKGxjLCBmKSwgcXVlIHJlY2liZSBjb21vIHBhcsOhbWV0cm9zIHVuYSBsaXN0YSBkZSByZWdpc3Ryb3MgeSB1bmEgZnVuY2nDs24gcXVlIGRlZmluZSBjw7NtbyBjb21iaW5hciBkb3MgY29udGFjdG9zLiBEZWJlbiB1dGlsaXphcnNlIGV4Y2x1c2l2YW1lbnRlIGxhbWJkYXMsIHkgcGFyYSBlc3RhIGZ1bmNpw7NuIGVuIHBhcnRpY3VsYXIsIHJlZHVjaXIgbGEgbGlzdGEuCgoJbGlzdGFkbyA9IGxpc3RhX2NvbnRhY3RvcyhbYzEsIGMyLCBjM10sIGxhbWJkYSBjMSwgYzI6IHN0cihjMSkgKyDigJxcbuKAnSArIHN0cihjMikpCglwcmludChsaXN0YWRvKQkJCQkJIyBCYWx0YXNhcuKApgoKIiIiCgoKaW1wb3J0IGNzdgoKY2xhc3MgQ29udGFjdG86CiAgICBkZWYgX19pbml0X18oc2VsZiwgbm9tYnJlLCBhcGVsbGlkb3MsIHRsZiwgZW1haWwpOgogICAgICAgIHNlbGYuX25vbWJyZSA9IG5vbWJyZQogICAgICAgIHNlbGYuX2FwZWxsaWRvcyA9IGFwZWxsaWRvcwogICAgICAgIHNlbGYuX3RsZiA9IHRsZgogICAgICAgIHNlbGYuX2VtYWlsID0gZW1haWwKICAgICAgICAKICAgIEBwcm9wZXJ0eQogICAgZGVmIG5vbWJyZShzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fbm9tYnJlCiAgICAKICAgIEBwcm9wZXJ0eQogICAgZGVmIGFwZWxsaWRvcyhzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fYXBlbGxpZG9zCiAgICAKICAgIEBwcm9wZXJ0eQogICAgZGVmIHRsZihzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fdGxmCiAgICAKICAgIEBwcm9wZXJ0eQogICAgZGVmIGVtYWlsKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLl9lbWFpbAogICAgCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgZnJvbV9jc3YoZik6CiAgICAgICAgcmVhZGVyID0gY3N2LnJlYWRlcihmKQogICAgICAgIGRhdGEgPSBuZXh0KHJlYWRlcikKICAgICAgICB0b3JldCA9IENvbnRhY3RvKGRhdGFbMF0sIGRhdGFbMV0sIGludChkYXRhWzJdKSwgZGF0YVszXSkKICAgICAgICByZXR1cm4gdG9yZXQKCiAgICBkZWYgdG9fY3N2KHNlbGYsIGYpOgogICAgICAgIHdyaXRlciA9IGNzdi53cml0ZXIoZikKICAgICAgICB3cml0ZXIud3JpdGVyb3coW3NlbGYubm9tYnJlLCBzZWxmLmFwZWxsaWRvcywgc2VsZi50bGYsIHNlbGYuZW1haWxdKQogICAgCiAgICBkZWYgX19nZXRhdHRyX18oc2VsZiwgcyk6CiAgICAgICAgaWYgcyA9PSAibm9tYnJlX2NvbXBsZXRvIjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuYXBlbGxpZG9zICsgIiwgIiArIHNlbGYubm9tYnJlCiAgICAgICAgZWxzZToKICAgICAgICAJcmFpc2UgQXR0cmlidXRlRXJyb3IocykKICAgIAogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgcmV0dXJuIHN0ci5mb3JtYXQoInt9ICh7fSk6IHt9Iiwgc2VsZi5ub21icmVfY29tcGxldG8sIHNlbGYudGxmLCBzZWxmLmVtYWlsKQogICAgCgpsaXN0YV9jb250YWN0b3MgPSBsYW1iZGEgbCwgZjooCiAgICAgICAgICAgICIiIGlmIG5vdCBsIG9yIGwgPT0gW10KICAgICAgICAgICAgZWxzZSBmKGxbMF0sIGxpc3RhX2NvbnRhY3RvcyhsWzE6XSwgZikpKQoKCmltcG9ydCB1bml0dGVzdAppbXBvcnQgaW8KCgpjbGFzcyBUZXN0Q29udGFjdG8odW5pdHRlc3QuVGVzdENhc2UpOgogICAgZGVmIHNldFVwKHNlbGYpOgogICAgICAgIHNlbGYuYzEgPSBDb250YWN0bygiQmFsdGFzYXIiLCAiR2FyY8OtYSIsIDk4ODM2ODg5MSwgImpiZ2FyY2lhQHV2aWdvLmVzIikKICAgICAgICBzZWxmLnRvZG9zX2NvbnRhY3RvcyA9IFtzZWxmLmMxXQogICAgICAgIHNlbGYudG9kb3NfcmVzdWx0YWRvcyA9IFsKICAgICAgICAgICAgIkdhcmPDrWEsIEJhbHRhc2FyICg5ODgzNjg4OTEpOiBqYmdhcmNpYUB1dmlnby5lcyIsCiAgICAgICAgXQogICAgICAgIAogICAgZGVmIHRlc3RDb250YWN0b1N0cihzZWxmKToKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKGxlbihzZWxmLnRvZG9zX3Jlc3VsdGFkb3MpLCBsZW4oc2VsZi50b2Rvc19jb250YWN0b3MpKQogICAgICAgIGZvciBpLCByZXN1bHRhZG8gaW4gZW51bWVyYXRlKHNlbGYudG9kb3NfcmVzdWx0YWRvcyk6CiAgICAgICAgICAgIHJlc3VsdGFkb19jb250YWN0byA9IFRlc3RDb250YWN0by5wcmVwYXJhX3Jlc3VsdGFkbyhzdHIoc2VsZi50b2Rvc19jb250YWN0b3NbaV0pKQogICAgICAgICAgICByZXN1bHRhZG8gPSBUZXN0Q29udGFjdG8ucHJlcGFyYV9yZXN1bHRhZG8ocmVzdWx0YWRvKQogICAgICAgICAgICBzZWxmLmFzc2VydEVxdWFsKHJlc3VsdGFkbywgcmVzdWx0YWRvX2NvbnRhY3RvKQogICAgICAgICAgICAgICAgICAgIAogICAgZGVmIHRlc3RDb250YWN0b05vbWJyZUNvbXBsZXRvKHNlbGYpOgogICAgICAgIGZvciBjIGluIHNlbGYudG9kb3NfY29udGFjdG9zOgogICAgICAgICAgICBub21icmVfY29tcGxldG8gPSBjLmFwZWxsaWRvcyArICIsICIgKyBjLm5vbWJyZQogICAgICAgICAgICBzZWxmLmFzc2VydEVxdWFsKCBub21icmVfY29tcGxldG8sIGMubm9tYnJlX2NvbXBsZXRvKQogICAgICAgIAogICAgZGVmIHRlc3RDb250YWN0b0NTVihzZWxmKToKICAgICAgICBmb3IgYyBpbiBzZWxmLnRvZG9zX2NvbnRhY3RvczoKICAgICAgICAgICAgd2l0aCBpby5TdHJpbmdJTygpIGFzIHM6CiAgICAgICAgICAgICAgICBjLnRvX2NzdihzKQogICAgICAgICAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCgiLCIuam9pbihbYy5ub21icmUsIGMuYXBlbGxpZG9zLCBzdHIoYy50bGYpLCBjLmVtYWlsXSksIHMuZ2V0dmFsdWUoKS5zdHJpcCgpKQogICAgICAgICAgICAKICAgIGRlZiB0ZXN0TG9hZEZyb21DU1Yoc2VsZik6CiAgICAgICAgZm9yIGksIGMxIGluIGVudW1lcmF0ZShzZWxmLnRvZG9zX2NvbnRhY3Rvcyk6CiAgICAgICAgICAgIHdpdGggaW8uU3RyaW5nSU8oIiwiLmpvaW4oW2MxLm5vbWJyZSwgYzEuYXBlbGxpZG9zLCBzdHIoYzEudGxmKSwgYzEuZW1haWxdKSkgYXMgZjoKICAgICAgICAgICAgICAgIGMyID0gQ29udGFjdG8uZnJvbV9jc3YoZikKICAgICAgICAgICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoYzEubm9tYnJlLCBjMi5ub21icmUpCiAgICAgICAgICAgICAgICBzZWxmLmFzc2VydEVxdWFsKGMxLmFwZWxsaWRvcywgYzIuYXBlbGxpZG9zKQogICAgICAgICAgICAgICAgc2VsZi5hc3NlcnRFcXVhbChjMS50bGYsIGMyLnRsZikKICAgICAgICAgICAgICAgIHNlbGYuYXNzZXJ0RXF1YWwoYzEuZW1haWwsIGMyLmVtYWlsKQogICAgICAgICAgICAKICAgIGRlZiB0ZXN0TGlzdGFSZWdpc3Ryb3Moc2VsZik6CiAgICAgICAgcmVzdWx0YWRvID0gbGlzdGFfY29udGFjdG9zKHNlbGYudG9kb3NfY29udGFjdG9zLCBsYW1iZGEgeCwgeTogc3RyKHgpICsgIlxuIiArIHN0cih5KSkuc3RyaXAoKQogICAgICAgIHRvZG9zX3Jlc3VsdGFkb3MgPSAiXG4iLmpvaW4oW3N0cihjKSBmb3IgYyBpbiBzZWxmLnRvZG9zX2NvbnRhY3Rvc10pCiAgICAgICAgc2VsZi5hc3NlcnRFcXVhbCh0b2Rvc19yZXN1bHRhZG9zLCByZXN1bHRhZG8pCiAgICAgICAgCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHJlcGFyYV9yZXN1bHRhZG8ocyk6CiAgICAgICAgcmV0dXJuIHMuc3RyaXAoKS5yZXBsYWNlKCdcJycsICciJykucmVwbGFjZSgnICcsICIiKQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICB1bml0dGVzdC5tYWluKCkK