Introducciónalaprogramaciónorientadaaobjetos conpython
Notasacercadeesteartículo Esteartículohasidoextraídodelapáginawebhttp://blog.rvburke.comcumpliendoconlanormadecopyright establecida. Copyright RafaelVillarBurke,2006.Sepermiteladistribución,copiaymodificacióndelostextos, siempreycuandoseindiquenloscambiosrealizados,seconserveelcopyrightyestanota. SuautororiginalesRafaelVillarBurkeyelartículodatadel22deNoviembrede2006.LaversiónenPDFhasido realizadaporoscarcarballalpregoydatadel24denoviembrede2009. Sehaprocedidoahaceralgunasconcesionesvisualesdecaraaorientarallectordeformamásintuitivaaloque estáviendoencadamomento.lostextoscontenidosencajasgrisesserefierenalíneasdecódigo,ylostextos contenidosencajasconbordenegrosonlasrepresentacionesdelosdatosquedeberíansalirporpantalla.esto sejuntaconlasconcesionesyaestablecidasenelartículooriginal,lascualessonmostradasmásabajo. Icode,thereforeIam.
Esteartículoesunaintroducciónalaprogramaciónorientadaaobjetos(POO,oOOPporsussiglaseninglés), unodelosparadigmasdeprogramaciónestructuradamásimportantehoyendía. ElartículousaellenguajePythonparalosdistintosejemplos,yexplicalaimplementacióndelaPOOenese lenguaje,aunqueabordaconceptosgeneralesquesonfácilmentetrasladablesaotroslenguajes. Losfragmentosdecódigoseseñalanusandounestilodetextodiferente(anchofijo)y,cuandoseutilizael intérpretedepython,seprefijacadalíneaconlossímbolos >>>.Estaintroducciónpresuponeconocimientos básicosdeprogramaciónydellenguajepython. Formasdepensar:paradigmasdeprogramación Unodeloselementosbásicosalahoraderealizarunprogramaeslamodelizacióndelproblemaquepretende resolver.esprecisolocalizarlasvariablesylosaspectosrelevantes,asícomocomprenderlospasosnecesarios paraobtenerelresultadoapartirdelosdatosiniciales,etc.esdecir,abstraerelproblema,reduciendosus detallesdeformaquepodamostrabajarconpocoselementoscadavez. Laalgoritmiaplantealaformaóptimaderesolverproblemasconcretos,talescomolaordenacióndeunalistade elementos,labúsquedadeunelementoenunconjunto,lamanipulacióndeconjuntosdedatos,etc.sin embargo,noproporcionanunmarcogeneral,unenfoque,quenospermitaplantearyformularlassolucionesa unproblemadeformacoherente. Losparadigmasdeprogramaciónllenanesehueco,proporcionandoguíastantosobrecómorealizarla abstraccióndelosdatoscomosobreelcontroldelaejecución.esdecir,losparadigmasdeprogramaciónson herramientasconceptualesparaanalizar,representaryabordarlosproblemas,presentando sistematizacionesalternativasocomplementariasparapasardelespaciodelosproblemasaldelas implementacionesdeunasolución. Esmuyrecomendableyproductivocomprenderelenfoquededistintosparadigmas,puestoquepresentan estrategiasalternativas,incrementandonuestrasherramientasdisponiblesyhaciéndonoreflexionarsobre muchasdelastareasquerealizamosalcrearunprograma.además,amenudoocurrequeunosproblemasse formulandeformamuyclarasiselosanalizasegúnunaperspectivadeterminada,mientrasqueproducenuna grancomplejidadvistosdeotramanera. Algunosparadigmashabituales Algunasdelasformasdepensarlosproblemasquehallegadoasistematizarsecomoparadigmasde programaciónson: Laprogramaciónmodular:Losprogramasseformanporpartesseparadasllamadasmódulos.Estos funcionandeformaindependienteentresí,oserelacionanatravésdeinterfacesbiendefinidas.
Laprogramaciónprocedural:Unprogramasecomponedeprocedimientos(subrutinas,métodoso funciones)quesonfragmentosdecódigoquepuedenllamarsedesdecualquierpuntodelaejecución deunprograma,incluídosotrosprocedimientosoélmismo.(ej.algol) Laprogramaciónestructurada:Sepuedeexpresarcualquierprogramautilizandoúnicamentetres estructurasdecontrol:secuencial,condicionaleiterativa.losprogramassecomponendepartes menoresconunúnicopuntodeentrada,ysetratadeaislarlosparaevitarlacomplejidadque introducenlosefectoscolaterales.(ej.pascal,c,ada) Laprogramaciónimperativa:Unprogramasepuededefinirentérminosdeestado,ydeinstrucciones secuencialesquemodificandichoestado.(ej.c,basic) Laprogramacióndeclarativa:Esposibleexpresarunprogramaatravésdecondiciones,proposicioneso restricciones,apartirdelosqueseobtienelasoluciónmediantereglasinternasdecontrol.(ej. PROLOG) Laprogramaciónfuncional:Sepuedeexpresarunprogramacomounasecuenciadeaplicacióndefunciones. Eludeelconceptodeestadodelcómputoynoprecisadelasestructurasdecontroldelaprogramación estructurada.(ej.lisp,haskell) Laprogramaciónorientadaaobjetos:Losprogramassedefinenentérminosde clasesdeobjetos quese comunicanentresímedianteelenvíodemensajes.esunaevolucióndelosparadigmasdela programaciónprocedural,estructuradaymodular,yseimplementaenlenguajescomojava, Smalltalk,PythonoC++. Programaciónmultiparadigma Losparadigmasdeprogramaciónsonidealizaciones,y,comotales,nosiempresepresentandeforma totalmente pura,nisiempreresultanincompatiblesentresí.cuandoseentremezclandiversosparadigmasse produceloqueseconocecomoprogramaciónmultiparadigma. Elusodedistintosmodelos,segúnseadaptenmejoralasdiversaspartesdeunproblemaoanuestraformade pensamiento,resultatambiénmásnaturalypermiteexpresardeformamásclarayconcisanuestrasideas. Algunoslenguajes,comoHaskelloPrologestándiseñadosparaencajarperfectamenteenlavisióndeun paradigmaparticular,mientrasqueotros,comopython,seadaptanespecialmentebienalaprogramación multiparadigmaydangranlibertadalahoraderesolverunproblema,alnoimponenunmismopatrónpara todosloscasos. Tiposdedatos Unaformadealmacenaryrepresentarunafechaenunprogramapodríaserlasiguiente: d = 14 m = "Noviembre"
a = 2006 def dime_fecha(dia, mes, anho): return "%i de %s de %i del calendario gregoriano" % (dia, mes, anho) print fecha(d, m, a) paraobtenerlasiguientesalida: "14deNoviembrede2006" Enesteejemplo,pararepresentarymanipularloqueconceptualmenteentendemoscomounafecha,seutilizan lasvariablesd,myacomoalmacenesdedatos,yunprocedimientoofunción,denombredime_fecha,para realizarlarepresentacióndelafechaalmacenada. Lasvariablespermitenalmacenartiposdedatosconcretoscomolosenteros(dya)olascadenasdetexto(m),y lafunciónrealizasutrabajodevolviendootrotipoconcreto,unacadenadetexto. Unodelosproblemasdeesteenfoqueesquenoreflejademasiadobienelconceptofechaqueusamoscomo modelomentalalimplementarlocomounconjuntodetresvariablesnorelacionadasentresí(d,mya).esdecir, lastresvariablestienenunaunidadconceptualennuestramente,quenosereflejaenlaformadeexpresarel problema.delamismamanera,lafuncióndime_fechadesconoceigualmentelarelaciónentresusparámetros, quepodríasertotalmentearbitraria. Estasituación,quepuedeparecerunacuestiónde estilo,implicaunriesgodeproblemasdesincronización entrevariables relacionadas,dispersiónendistintaspartesdelcódigodemanipulacionesquesonrelevantesal conjunto,pérdidadelvalorsemánticodecadavariablequepuededarlugaraerroresaltransformarelcódigo Unejemplodedesconexiónsemánticaentrelaimplementaciónyelconceptoesquedpuedesercualquiervalor entero,mientrasqueundíatieneunvalorsituadoentre1y31,mesunacadenadetextodentrodeunnúmero limitadodeopciones,oanopuedetomarvaloresnegativos.porsupuestoqueestosepodríasolucionarcon códigoquehiciesecomprobacionesadicionales,peroenestecasoqueremosresaltarcómounprogramaesun modeloaproximadoaunproblemaycómoseríapreferiblequelaimplementaciónpudieserepresentardeforma másajustadaelcomportamientodelmodeloelegido. Unaposiblesoluciónseríadisponerdeuntipodedatosquerepresentedeformamásadecuadaelconceptode fechayquenospermitamanipularfechasdelamismamaneraquemanipulamosnúmerosenteros,números realesocadenasdetexto,independientementedelaimplementacióninternaquelossustente. Clasesyobjetos Alenunciaralgunostiposdeparadigmashemosvistoquelaprogramaciónorientadaaobjetosdefinelos programasentérminosde clasesdeobjetos quesecomunicanentresímedianteelenvíodemensajes.en esteapartadoaclararemosquéseentiendeenesecontextoporclasesyobjetos. Lasclasessurgendelageneralizacióndelostiposdedatosypermitenunarepresentaciónmásdirectadelos conceptosnecesariosparalamodelizacióndeunproblemapermitiendodefinirnuevostiposalusuario. Lasclasespermitenagruparenunnuevotipolosdatosylasfuncionalidadesasociadasadichosdatos, favoreciendolaseparaciónentrelosdetallesdelaimplementacióndelaspropiedadesesencialesparasuuso.a
estacualidad,denomostrarmásquelainformaciónrelevante,ocultandoelestadoylosmétodosinternosdela clase,esconocidacomo encapsulación,yesunprincipioheredadodelaprogramaciónmodular. Unaspectoimportanteenelusodeclasesesquenosemanipulandirectamente(salvoenloqueseconoce comometaprogramación),sinoquesirvenparaladefiniciónnuevostipos.unaclasedefinepropiedadesy comportamientoquesemuestranenlosentesllamadosobjetos(oinstanciasdeunaclase).laclaseactúa comomoldedeunconjuntodeobjetos,delosquesedicequepertenecenalaclase. Trasladandoestosconceptosalosnúmerosenteros(tipoint),sepuededecirquelasvariablesquealmacenan númerosenterossonobjetosoinstanciasdelaclaseintoquepertenecenalaclaseint. Entérminosmásabstractos,podemospensarenlasclasescomodefinicionesyenlosobjetoscomoexpresiones concretasdedichasdefiniciones. Fisonomíadeunaclase Enpython,elesquemaparaladefinicióndeunaclaseeselsiguiente: class NombreClase: <instrucción_1>... <instrucción_n> endondeclassesunapalabrareservadaqueindicaladeclaracióndeunaclase,nombreclaseunaetiquetaque danombrealaclasey,losdospuntos,queseñalaneliniciodelbloquedeinstruccionesdelaclase. Elcuerpodeinstruccionesdelaclasepuedecontenertantoasignacionesdedatoscomodefinicionesde funciones.estebloquedeinstruccionesseencuentraenelnuevoespaciodenombresconelnombredelaclase, quesegenera,asuvez,conlacreacióndecadaobjeto.enamboscasos,enelespaciodenombresdelaclasey delobjeto,esposibleaccederaloselementosquelointegranusandoeloperadorpunto,comoenelcasodelos espaciosdenombresdeunmódulo(e.j.math.pi,objeto.dato,objeto.funcion()). Silaprimerainstruccióndelcuerpodelaclaseesunacadenadetexto,éstaseusacomocadenade documentacióndelaclase. Nuestroejemplopodríareescribirseentérminosdeunaclaseasí: class Fecha: "Ejemplo de clase para representar fechas" dia = 14 mes = "Noviembre" anho = 2006 def dime_fecha(self): return "%i de %s de %i" % (Fecha.dia, Fecha.mes, Fecha.anho) mi_fecha = Fecha() print mi_fecha.dia, mi_fecha.mes, mi_fecha.anho print mi_fecha.dime_fecha()
EnelfragmentodecódigoanteriordefinimoslaclaseFechayellaasignamosvaloresalasetiquetasdia,mesy anho(atributosdelaclase),ydefinimosunafunción(unmétododelaclase),dime_fecha. Fueradeladefinicióndelaclasecreamos(instanciamos)unobjetopertenecientealaclaseFecha.Esta instanciaciónserealizautilizandolanotacióndellamadaafunción,ypodemosentenderlacomounallamadaa unafunciónquedevuelveunobjetodelaclasefecha.elobjetoobtenidoesasignadoalaetiquetami_fecha. Enlasiguientesinstruccionesmostramosporpantallalosvaloresdelaspropiedadesdia,mesyanhoyel resultadodelallamadaalmétododime_fecha,usandoeloperadorpuntoparaaccederalaspropiedadesy métodosdelobjetomi_fecha,yaque,comohemosmencionadoantes,formanpartedelespaciodenombresdel objeto. Lallamadaalmétododime_fechanoincluyeningúnparámetro,peropodemoscomprobarque,deforma contradictoria,ladeclaracióndelmétodoindicauno,self.esteparámetroesañadidoautomáticamenteporel intérpreteenlasllamadasalosmétodosdeunaclase,ycontieneunareferenciaalobjetoquerecibelaseñal(el querecibeunallamadaaunmétodo).selfpermiteaccederalaspropiedadesymétodosdeunobjetoconcretoy aclararemossusignificadoyusomásadelante.porahoranosbastasaberqueesnecesarioincluirselfcomo primerparámetrodelosmétodosdefinidosenunaclaseyquenoesprecisoincluirelparámetroimplícito selfalrealizarllamadasaunmétodoatravésdelobjetoalquepertenece. Enrealidad,enelejemploanterior,lallamadami_fecha.dime_fecha()esunaformamáscómodadeescribir (azúcarsintáctico)fecha.dime_fecha(mi_fecha),loqueexplicalapresenciadelparámetro. Unpaseoentreobjetos Hastaelmomentohemosvistocómolasclasesdefinenlosdatos(oestado)ycomportamientodelosobjetosa travésdeatributos(opropiedades)ymétodos. Ahoravamosahacerunrecorrido,utilizandounasesióninteractivadelintérpreteylascapacidadesde introspeccióndepython,paraexplicarelusoyelcomportamientodelosobjetos. Veremosalgunascaracterísticasdelosobjetos: Identidad.Losobjetossediferencianentresí,deformaquedosobjetos,creadosapartirdelamismaclasey conlosmismosparámetrosdeinicialización,sonentesdistintos. Definensucomportamiento(yoperarsobresusdatos)atravésdemétodos,equivalentesafunciones. Definenoreflejansuestado(datos)atravésdepropiedadesoatributos,quepuedensertiposconcretosu otrosobjetos. Pasamosaverunasesióninteractivadelintérprete: >>> mi_fecha = Fecha()
>>> mi_fecha_2 = Fecha() >>> mi_fecha is mi_fecha_2 False >>> print mi_fecha < main.fecha instance at 0x00B184B8> >>> print mi_fecha_2 < main.fecha instance at 0x00B18328> Vemosquetantomi_fechacomomi_fecha_2soninstanciasdelaclaseFecha(enelmódulo main )ycada unatienesupropioespaciodememoriaindependiente. >>> print mi_fecha.dime_fecha() 14 de Noviembre de 2006 >>> print mi_fecha.dia 14 >>> print mi_fecha_2.dia 14 >>> Fecha.dia = 16 >>> print Fecha.dia 16 >>> print mi_fecha.dia 16 >> print mi_fecha_2.dia 16 >>> mi_fecha.dia = 30 >>> print Fecha.dia 16 >>> print mi_fecha.dia 30 >>> print mi_fecha_2.dia 16 Esteúltimoexperimentoobservamoscómo,peseaquemi_fechaymi_fecha_2sondosinstanciasdistintasdela clasefecha,ambashacenreferenciaatravésdesuatributodiaalmismovalordelaclasefecha.dia.sin embargo,cuandoseproduceunaasignaciónaeseatributo(aesaetiqueta,enrealidad)enunodelosobjetos vemoscómo,apartirdeentonces,eseobjetodisponedeunvalor'individual'asociadoalatributo. Esecomportamientorevelalaexistenciadeatributos(oestado)compartidosportodaslasinstanciasdeuna claseydeatributos(oestado)ligadosaunainstanciaparticular.losprimerossesitúanenelespaciode nombresdelaclase,yvemoscómosepuedenhacerasignacionesenlasesióninteractivaanterior,olecturas,en elmétododime_fechadelejemploanterior.lossegundossesitúanenelespaciodenombresdecadaobjeto,y ahíesdonderesultaútilelparámetroself. Antesdeproseguir,podemosescudriñarquésímbolossonaccesiblesyquécontienenlosespaciosdenombres delaclasefechaydelosobjetosmi_fechaymi_fecha_2.usamoslafuncióndirparaloprimero,yelatributo dict paralosegundo,yaqueenpythonlosespaciosdenombresseimplementancomodiccionarios: >>> dir(fecha) [' doc ', ' module ', 'anho', 'dia', 'dime_fecha', 'mes'] >>> dir(fecha3) [' doc ', ' module ', 'anho', 'dia', 'dime_fecha', 'mes'] >>> dir(fecha4) [' doc ', ' module ', 'anho', 'dia', 'dime_fecha', 'mes'] Enlostrespodemosaccederalosmismossímbolos.Sinembargo... >>> Fecha. dict {' module ': ' main ', 'anho': 2006, 'dime_fecha': x00b176f0>, 'dia': 14, 'mes': 'Noviembre', ' doc ': 'Ejemplo de clase para representar fechas'} >>> mi_fecha_2. dict {} >>> mi_fecha. dict {'dia': 30} Elespaciodenombresdelaclaseeselquealbergalosnombresdelosatributosymétodosindicadosenla declaracióndelaclase,ademásdelosatributosespeciales doc,quecontienelacadenadedocumentacióny
module,quecontieneelnombredelmóduloalquepertenecelaclase.esossímbolossonaccesibles tambiénparalosobjetospertenecientesalaclase(talcomonosindicabadir()). Podemosvertambiénqueelespaciodenombresdelobjetomi_fecha_2seencuentravacío,mientrasqueeldel objetomi_fechacontieneelatributodía.estosedebeaqueanteriormenterealizamosunaasignaciónal atributodiadelobjetomi_fecha(dándoleelvalor30).elespaciodenombresrecogeesaversiónparticulardel atributo,quenoapareceenelotroobjeto,puestoqueaccedealatributodeclase. Alosatributoscompartidosportodoslosobjetosdeunaclaseselosdenominaatributosdeclase,cuandose deseadiferenciarlosdelosatributosquepertenecenacadainstanciaenparticular. Accesoindividualizadoaobjetos:self Ahoraquehemosvistocómousaratributosdeclaseparacompartirdatosentretodoslosobjetosdeunamisma clase,tambiénnosinteresaconocercómoutilizaratributoscomunesaunaclaseperoquepuedantomarvalores distintosparacadaunodelosobjetos. Retomamosahoraelmisteriosoparámetroselfquevimosestabapresentecomoprimerparámetrodetodoslos métodosdeunaclase.ensumomentoyacomentamosqueselfcontieneunareferenciaalobjetoquerecibela señal(elobjetocuyométodoesllamado),porloquepodemosusaresareferenciaparaaccederalespaciode nombresdelobjeto,esdecir,asusatributosindividuales. >>> class F:... i = 5... def dime_i(self):... return F.i... def dime_mi_i(self):... return self.i... >>> a = F() >>> a.dime_i() 5 >>> a.dime_mi_i() 5 >>> a.i = 6 >>> a.dime_i() 5 >>> a.dime_mi_i() 6 >>> a.i 6 Enesteejemploelmétododime_iusaelatributodeclaseyretornasuvalor,5,mientrasqueelmétodo dime_mi_iusaunareferenciaalobjetoydevuelveelvalor6,elasignadoalatributodelobjetoa.asíaccedemos selectivamentealatributodeclaseioalatributodeinstanciai. Algoquepuedeaclararalgomáslanaturalezadelparámetroself,esrecordarque,cuandohacemosunallamada aunmétodoun_metododeunobjetoun_objetopertenecientealaclaseunaclase,elintérpretetraducela expresiónun_objeto.un_metodo()comounaclase.un_metodo(un_objeto). Elusodeselfrespondealaformaparticularenquepythonimplementaelsoportedeobjetos,aunquelenguajes
comojavaoc++utilizanmecanismossimilaresconlapalabrareservadathis.enpythonselfnoesunapalabra reservadaycualquieretiquetausadacomoprimerparámetrovaldríaigualmente,aunquesedesaconseja totalmenteelusodeotrasetiquetas,portratarsedeunaconvenciónmuyarraigadaenellenguajequehaceel códigomáslegible,facilitaelresaltadodesintaxis,etc. Elmétododeinicialización init Hemosvistoyacómodefiniryusaratributosdeclaseydeinstancia.Peroenpythonnoesnecesariala declaracióndevariables,porloquecualquieratributoalqueserealiceunaasignaciónenelcódigoseconvierte enunatributodeinstancia: >>> a = F() >>> a.i = 6 >>> a.atr = 3 >>> print a.atr 3 >>> a. dict {'i': 6, 'atr': 3} Unafuncionalidadmuyconvenientequehemosvistoenladeclaracióndeatributosdeclaseesladerealizarsu inicializaciónenelcuerpodelaclase.parapoderinicializarlosatributosdeunainstanciaexisteunmétodo especialquepermiteactuarsobrelainicializacióndelobjeto.dichométodosedenomina init (condos guionesbajosalprincipioyalfinal)yadmitecualquiernúmerodeparámetros,siendoelprimerolareferenciaal objetoqueesincializado(self,porconvención),quenospermiterealizarlasasignacionesaatributosdela instancia.estemétodoseejecutasiemprequesecreaunnuevoobjetodelaclase,traslaasignaciónde memoriayconlosatributosdeclaseinicializados,ysecorrespondeparcialmenteconelconceptode constructordelaclaseexistenteenotroslenguajes. Conlareferenciaquenosproporcionaselfpodemosinicializaratributosdeinstancia,convalores predeterminadossilodeseamos,comoencualquierdefinicióndefunción: class Clase: def init (self, x=2): self.x = x self.a = x**2 self.b = x**3 self.c = 999 def dime_datos(self): return "Con x=%i obtenemos: a=%i, b=%i, c=%i" % (self.x, self.a, self.b, self.c) a1 = Clase(2) a1.dime_datos() a2 = Clase(3) a2.dime_datos() Salida: Conx=2obtenemos:a=4,b=8,c=999Conx=3obtenemos:a=9,b=27,c=999 PropiedadesyAtributos Aunqueenlaterminologíageneraldelaprogramaciónorientadaaobjetosatributoypropiedadsepueden utilizarcomosinómimos,enpythonseparticularizaelusodepropiedadesparauntipoespecialdeatributos
cuyoaccesoseproduceatravésdellamadasafunciones. class ClaseC(object): def init (self): self. b = 0 def get_b(self): return self. b def set_b(self, valor): if valor > 10: self. b = 0 else: self. b = valor b = property( get_b, set_b, 'Propiedad b') c1 = ClaseC() print c1.b # b es 0 c1.b = 5 print c1.b # b es 5 c2 = ClaseC() print c2.b # b es 0 c2.b = 12 print c2.b #b es 0 Enesteejemplosedefinelapropiedadb,cuyocomportamientoes:cuandoserealizaunaasignación,tomael valorentregadosiesmenorque10,o0encasocontrario,yloalmacenaenunatributoprivado b.cuandose producelalecturadeb,devuelveelvalorguardadoenelatributoprivado. EnPython,parapoderusarpropiedadesenunaclaseesnecesariohacerladerivardelaclaseobjectdeahíque aparezcaalladodelnombredelaclaseclasec.enunapartadoposteriorseexplicaráenquéconsistela derivacióndeclases. Lasignaturadelafunciónproperty,quedefineunapropiedaddelaclaseeslasiguiente:nombre_propiedad= property(get_f,set_f,del_f,doc)dondeget_feslafunciónllamadacuandoseproducelalecturadelatributo; set_flafunciónllamadacuandoseproduceunaasignaciónalatributo;del_flafunciónllamadacuandose eliminaelatributo,ydocesunacadenadedocumentacióndelapropiedad. Laspropiedadesresultanmuyútilespararealizarlavalidacióndelosvaloresasignados,latransformacióno cálculodevaloresdevueltosy,además,dotandegranflexibilidadalahoradeescribirelcódigo,puestoquees posibleempezarusandoatributosyluegosustituirloporunapropiedadquerealicefuncionesadicionales,a medidaqueelcódigolorequieraysimplementecambiandoelcódigodelaclase,sinafectaralcódigoclientede laclase. Herenciayderivacióndeclases Vemosqueelusodeclaseshacemásadecuadalarepresentacióndeconceptosennuestrosprogramas. Además,esposiblegenerarunaclasenuevaapartirdeotra,delaquerecibesucomportamientoyestado (métodosyatributos),adaptándolosoampliándolossegúnseanecesario.
Deunaclasequerepresentaseelconceptodevehículopodríamosderivarotraspararepresentarautomóviles, bicicletas,barcosoaviones,dondecadaunodeellosmantieneatributosymétodoscomunes(peso,color, velocidadmáxima,númerodepasajeros),mientrasqueotrossonexclusivos(númeroderuedas,númerode hélices,númerodereactores,altitudmáximadevuelo...). Entérminosmatemáticospodemosexpresarlodiciendoqueesposibleestablecerrelacionesdepertenencia entreclases.sitenemosunaclaseaydeelladerivamosunaclaseb,podemosdecirque"besunaa",oque"bes unaespecializacióndea". EnlaterminologíadelaPOOsediceque"BheredadeA","BesunaclasederivadadeA","AeslaclasebasedeB", "AessuperclasedeB"o"AesclasemadredeB". Estofacilitalareutilizacióndelcódigo,puestoquesepuedenimplementarloscomportamientosydatosbásicos enunaclasebaseyespecializarlosenlasclasesderivadas. Enunprogramahipotéticoquetrabajaseconformasgeométricas,podríamostenerunaclasebaseFormay clasesderivadasdeellacomotriangulo,cuadrado,circulo...enlaclasebasepodríamosdefinirunmétododibuja querepresentalafiguraenpantalla,yunmétodoareayotroperímetroquecalculaneláreayelperímetro, respectivamente. Enellenguajepython,paraexpresarqueunaclasederiva,desciendeoesherederadeotrauotrasclasesse añadetraselnombre,enladeclaracióndelaclase,unatuplaconlosnombresdelasclasesbase. ElsiguienteejemplocreaunaClaseAydeelladerivaunaClaseBqueinicializaunatributoadicional,cambiael comportamientodeunmétodoyheredalosatributosdelaclasemadre: class ClaseA: def init (self, x): self.a = x self.b = 2 * x def muestra(self): print "a=%i, b=%i" % (self.a, self.b) class ClaseB(ClaseA): def init (self, x, y): ClaseA. init (self, x) self.c = 3 * (x + y) + self.b def muestra(self): print "a=%i, b=%i, c=%i" % (self.a, self.b, self.c) print "Objeto A" a = ClaseA(2) print a. dict a.muestra() print "ObjetoB" b = ClaseB(2, 3) print b. dict b.muestra()
Salida: ObjetoA {'a':2,'b':4} a=2,b=4 ObjetoB {'a':2,'c':19,'b':4} a=2,b=4,c=19 LaclaseClaseAmuestrafuncionalidadesqueyahemosidoviendoenestaintroducción(atributosdeinstanciaa yb,métodomuestra).laclaseclasebsedeclaracomodescendientedelaclasea,porloqueheredasus métodosyatributosymodificaalgoelcomportamientodelaclasemadre.porunaparte,ensumétodode inicializaciónllamaalmétododelaclasemadreconlosparámetrosdeseados,y,posteriomente,añadeun nuevoatributodeinstanciaquenoexisteenlaclasemadre.porotrolado,redefineunmétodoexistenteen ClaseA,cambiandolaimplementación. Estaúltimatécnica,enlaqueunmismonombreseasociaacomportamientosdistintosseconocecomo polimorfismo,ysehabladequeelmétodosehasobrecargado,esdecir,seleasignandistintossignificadosen funcióndesucontexto.elpolimorfismotambiénaludealaposibilidaddeutilizar,enuncontextoenelquese esperaunaclasedada,cualquierclasederivada. Laclaseobject Desdelaversión2.2depython,sehaestablecidounaclasebasellamadaobjectdelaqueseaconsejaderivar todaslasclases.estopermiteaprovecharunaseriedecaracterísticassóloexistentesenlas"nuevasclases" (comoladefinicióndepropiedades),quesedescribenenladocumentacióndepython. Enelejemplosobreelusodepropiedadesseintrodujolaherenciasinexplicarla,derivandolaclasedeobject. Ahoradeberíaestarmásclaralarazón. Jerarquíasdeclases Laherenciapermiteestablecerrelacionesentreclases,y,estasrelacionesdepertenenciapuedenseravarios niveles,yramificarseenloquesedenominanjerarquíasdeclases. Unejemplodeclásicoparavisualizarlasjerarquíasdeclaseseselquepodríaservirparamodelizarelconjuntode empleadosdeunaempresa.enellaapareceunaclasebaseempleado,quedisponedelosatributosnombrey departamento;deelladesciendenlassubclasesgestor(atributoadicionalinformes)ytrabajador(atributo adicionalproyectos),ydeestaúltimaderivanlasclasescomercial(atributoadicionalparticipación)eingeniero (atributooriginalarea). Gráficamentepodríarepresentarsedelasiguientemanera:
Eneldiagramasepuedeverennegritalosatributosqueimplementacadaclase,yengrislosqueheredade clasesmadre.elcódigo(básicodeinicialización)delasclasespodríaserelsiguiente: class Empleado: def init (self, nombre, departamento="general"): self.nombre = nombre self.departamento = departamento class Gestor(Empleado): def init (self, nombre): Empleado. init (self, nombre) self.informes = [] class Trabajador(Empleado): def init (self, nombre): Empleado. init (self, nombre) self.proyectos = [] class Comercial(Trabajador): def init (self, nombre, participacion=0.1): Trabajador. init (self, nombre) self.departamento = "ventas" self.participacion = participacion class Ingeniero(Trabajador): def init (self, nombre, area="mecánica"): Trabajador. init (self, nombre) self.departamento = "ingeniería" self.area = area Naturalmente,cadaunadelasclasestendríasuspropiosmétodosquedefiniríancomportamientospropiosde cadaclaseosubclase,quenosehandetalladoenelejemplo. Unaalternativaalaherenciaeslacomposición,enelqueunaclasesecomponedeotrasclasesinternas,yque puedeserunamejoralternativaenmuchoscasos. Encapsulaciónygradosdeprivacidad UnodelosprincipiosqueguíanlaPOO,heredadosdelaprogramaciónmodular,eseldeencapsulación.Hemos
vistocómosepuedeagruparcomportamientoydatosgraciasalusodeobjetos,perohastaelmomento,tanto losatributoscomolosmétodosquesedefinenenlasclasescorrespondientesseconviertenenmétodosy atributosvisiblesparalosusuariosdelaclase(laapidelaclase). Sedicequeunmétodooatributoespúblicosiesaccesibledesdeelexteriordelaclase,mientrasquese denominaprivadoencasocontrario. Esdeseablepoderseñalarquémétodosyatributosnodebenutilizarsefueradelaclaseparaevitarexponer excesivamentelosdetallesdelaimplementacióndeunaclaseounobjeto. Pythonutilizaparaelloconvencionesalahoradenombrarmétodosyatributos,deformaqueseseñalesu carácterprivado,parasuexclusióndelespaciodenombres,oparaindicarunafunciónespecial,normalmente asociadaafuncionalidadesestándardellenguaje. _nombre Losnombresquecomienzanconunúnicoguiónbajoindicandeformadébilunusointerno.Además,estos nombresnoseincorporanenelespaciodenombresdeunmóduloalimportarlocon"from...import*". nombre Losnombresqueempiezanpordosguionesbajosindicansuusoprivadoenlaclase. Porejemplo,enladefinicióndeclasesiguiente: class ClaseA: def init (self, a) self. a = a self.x = self. a**2 + 2 self.y = self. a**3 + 3 elatributo aesdeusointernodelaclaseynoseexportadirectamente.acontinuaciónpodemosvercómo tratalosatributos'privados'python: >>> a = ClaseA(2) >>> dir(a) ['_ClaseA a', ' doc ', ' init ', ' module ', 'x', 'y'] >>> a. dict {'x':6, 'y':11, '_ClaseA a':2} Todavíaesposibleaccedera a,peroelnombreestransformadoa'_clasea a',queloseñalacomoun atributodeusoprivado. nombre Losnombresqueempiezanyacabancondosguionesbajosindicanatributos"mágicos",deusoespecialyque residenenespaciosdenombresquepuedemanipularelusuario.solamentedebenusarseenlamaneraquese describeenladocumentacióndepythonydebeevitarselacreacióndenuevosatributosdeestetipo.
Algunosejemplosdenombres"singulares"deestetiposon: init,métododeinicializaciónde objetos del,métododedestruccióndeobjetos doc,cadenadedocumentacióndemódulos, clases... class,nombredelaclase str,métodoquedevuelveunadescripcióndelaclasecomocadena detexto repr,métodoquedevuelveunarepresentacióndelaclasecomocadenadetexto module, móduloalquepertenecelaclasesepuedeconsultarlalistadeatributosdeestetipoysudescripcióndetallada enladocumentacióndepython. Resúmenfinal Laprogramaciónorientadaaobjetosenuncialaposibilidaddeescribirunprogramacomounconjuntodeclases deobjetoscapacesdealmacenarsuestado,yqueinteractúanentresíatravésdelenvíodemensajes. Lastécnicasmásimportantesutilizadasenlaprogramaciónorientadaaobjetosson: Abstracción:Losobjetospuedenrealizartareas,interactuarconotrosobjetos,omodificareinformarsobre suestadosinnecesidaddecomunicarcómoserealizandichasacciones. Encapsulación(uocultacióndelainformación):losobjetosimpidenlamodificacióndesuestadointernoola llamadaamétodosinternosporpartedeotrosobjetos,ysolamenteserelacionanatravésdeuna interfazclaraquedefinecómoserelacionanconotrosobjetos. Polimorfismo:comportamientosdistintospuedenestarasociadosalmismonombre Herencia:losobjetosserelacionanconotrosestableciendojerarquías,yesposiblequeunosobjetoshereden laspropiedadesymétodosdeotrosobjetos,extendiendosucomportamientoy/oespecializándolo. Losobjetosseagrupanasíenclasesqueformanjerarquías. Lasclasesdefinenelcomportamientoyestadodisponiblequeseconcretaenlosobjetos. Losobjetossecaracterizanpor: Teneridentidad.Sediferencianentresí. Definirsucomportamientoatravésdemétodos. Definiroreflejarsuestadoatravésdepropiedadesyatributos.