Advertisement
  1. Code
  2. Python

Python desde Cero: Programación Orientada a Objetos

Scroll to top
Read Time: 15 min
This post is part of a series called Python from Scratch.
Python from Scratch - Functions and Modules
Python From Scratch: Create a Dynamic Website

Spanish (Español) translation by Leareny Guerrero (you can also view the original English article)

Bienvenidos a la lección cuatro de nuestra serie Python desde Cero. Este tutorial asumirá algunos conocimientos previos de variables, tipos de datos, funciones y resultados de impresión. Si no está actualizado, consulte los tres artículos anteriores de la serie para ponerse al día.

Hoy, vamos a profundizar en el tema de la Programación Orientada a Objetos (POO). POO es una forma muy poderosa de organizar su código, y una sólida comprensión de los conceptos subyacentes puede ayudarlo a obtener el máximo provecho de su codificación.


¿Prefieres un Screencast (Grabación de lo que se observa en la pantalla)?


Transcripción


¿Qué es la Programación Orientada a Objetos?

Python está diseñado principalmente como un lenguaje de programación orientado a objetos-- pero ¿qué significa realmente "orientado a objetos"?

Hay una variedad de definiciones para el término, y podría hablar literalmente durante horas tratando de explicar los complicados detalles, los matices y las diferencias en las implementaciones, pero trataré de dar una visión general rápida.

En términos generales, la programación orientada a objetos es el concepto de que, en la programación, los objetos que estamos manipulando son más importantes que la lógica necesaria para manipular esos objetos. Tradicionalmente, un programa se ha visto como una receta: un conjunto de instrucciones que se siguen de principio a fin para completar una tarea. Eso todavía puede ser cierto, y para muchos programas simples, eso es todo lo que se requiere. Ese enfoque a veces se conoce como programación de procedimiental.

POO pone los objetos en el centro del proceso.

Por otro lado, a medida que los programas se vuelven cada vez más complejos e intrincados, la lógica necesaria para escribirlos de una manera puramente procedimental se vuelve cada vez más torcida y difícil de entender. A menudo, los enfoques orientados a objetos pueden ayudar con eso.

Cuando hablamos de enfoques orientados a objetos, lo que hacemos es poner los objetos en el centro del proceso, en lugar de simplemente usarlos como contenedores necesarios para información como parte de nuestras instrucciones de procedimentales. Primero, definimos los objetos que queremos manipular y cómo se relacionan entre sí, y luego comenzamos a desarrollarlo con lógica para que el programa realmente funcione.

Cuando hablo de 'objetos', puedo estar hablando de todo tipo de cosas. Un 'objeto' puede representar a una persona (definida por propiedades como el nombre, la edad, la dirección, etc.) o una empresa (tal como lo define el número de empleados, etc.) o incluso algo mucho más abstracto, como botón en una interfaz de computadora.

En esta introducción, no cubriremos todos los conceptos en este tema porque estaríamos aquí toda la noche, pero para el final del tutorial, espero que tenga una comprensión sólida de los principios que necesita. para comenzar de inmediato utilizando algunas técnicas simples orientadas a objetos en sus programas de Python. Aún mejor, estos conceptos son bastante similares en muchos entornos de programación. El conocimiento se transfiere de un lenguaje a otro bastante bien.


Empezando

Mencioné anteriormente que lo primero que debemos hacer cuando nos dirigimos a un enfoque de POO es definir los objetos que vamos a utilizar. La forma en que hacemos esto es definir primero las propiedades que posee utilizando una clase. Puedes pensar en una clase como una especie de plantilla; una guía para la forma en que un objeto debe ser estructurado. Cada objeto pertenece a una clase y hereda las propiedades de esa clase, pero actúa individualmente con los otros objetos de esa clase.

Un objeto a veces se conoce como una 'instancia' de una clase.

Como ejemplo simple, puede tener una clase llamada 'persona', por ejemplo, con una propiedad edad y una propiedad nombre, y una instancia de esa clase (un objeto) sería una sola persona. Esa persona podría tener el nombre de "Andy" y una edad de 23 años, pero simultáneamente podría tener otra persona que pertenezca a la misma clase con el nombre de "Lucy" y una edad de 18 años.

Es difícil entender esto sin verlo en la práctica, así que vamos a ver un código real.

Definiendo una clase

Para definir una clase, en la forma típica de Python simple, usamos la palabra 'class', seguido del nombre de su nueva clase. Voy a hacer una nueva clase aquí, llamada 'mascota'. Usamos dos puntos después del nombre, y todo lo que está contenido dentro de la definición de class está indentado. Sin embargo, con una clase, no hay paréntesis:

Entonces ahora tenemos una clase, pero es bastante inútil sin nada en ella. Para empezar, vamos a darle un par de propiedades. Para hacer esto, simplemente define algunas variables dentro de la class - Voy a ir con el número de patas para comenzar. Como de costumbre, siempre debe nombrar sus variables para que sea fácil decir cuáles son. Seamos originales y llámenosla 'number_of_legs'. Necesitamos definir un valor o obtendremos un error. Usaré 0 aquí (no importa demasiado en este caso, ya que el número de patas será específico para cada instancia de la clase-- un pez no tiene la misma cantidad de patas que un perro o un pato, etc.-- así que tendremos que cambiar ese valor para cada objeto de todos modos).

Instancias y variables miembro

Una clase en sí misma no es algo que puedas manipular directamente; primero, tenemos que crear una instancia de la clase para jugar con esta. Podemos almacenar esa instancia en una variable. Fuera de la clase (sin ninguna indentación), hagamos una instancia de la clase y guárdela en la variable, 'doug'. Para crear una nueva instancia de una clase, simplemente escriba el nombre de la clase y luego un par de paréntesis. En este punto, no hay necesidad de preocuparse por los paréntesis, pero más adelante verá que están ahí porque, como una función, hay una forma de pasar una variable para que la use la clase cuando crea la instancia por primera vez.

Una clase en sí misma no es algo que puedas manipular directamente.

Ahora que tenemos una instancia de una clase, ¿cómo accedemos y manipulamos sus propiedades? Para hacer referencia a una propiedad de un objeto, primero tenemos que decirle a Python qué objeto (o qué instancia de una clase) estamos hablando, así que vamos a comenzar con 'doug'. Luego, vamos a escribir un punto para indicar que estamos haciendo referencia a algo que está dentro de nuestra instancia de doug. Después del punto, agregamos el nombre de nuestra variable. Si estamos accediendo a la variable number_of_legs, se verá así:

Podemos tratar eso ahora exactamente como trataríamos cualquier otra variable -- aquí voy a suponer que doug es un perro, y le daré a esa variable el valor de 4.

Para acceder a esta variable, vamos a usarla de nuevo exactamente como trataríamos cualquier otra variable, pero usando esa propiedad doug.number_of_legs en lugar del nombre de la variable normal. Hagamos una línea para imprimir cuántas patas tiene para que podamos demostrar que está funcionando como debería:

Si ejecuta el código anterior, verá lo que se imprimió para nosotros. Definió nuestra clase 'pet', creó una nueva instancia de esa clase y la almacenó en la variable 'doug', y luego, dentro de esa instancia, se le asignó el valor de 4 a la variable number_of_legs que heredó de su clase.

Entonces, a partir de ese ejemplo muy simple, puede ver cómo puede comenzar a construir estructuras de datos agradables y modulares que sean claras y fáciles de usar, y que puedan comenzar a escalar bastante bien.


Introduciendo la Lógica

Bueno, eso es lo básico de las clases y los objetos, pero por el momento solo podemos usar las clases como estructuras de datos, o contenedores para las variables. Eso está muy bien, pero si queremos comenzar a realizar tareas más complejas con los datos que estamos manipulando, necesitamos una forma de introducir algo de lógica en estos objetos. La forma en que hacemos eso es con métodos.

Los métodos, esencialmente, son funciones contenidas dentro de una clase. Usted define uno exactamente de la misma manera que lo haría con una función, pero la diferencia es que la coloca dentro de una clase y pertenece a esa clase. Si alguna vez quiere llamar a ese método, primero debe hacer referencia a un objeto de esa clase, al igual que las variables que estábamos viendo previamente.

Los métodos, esencialmente, son funciones contenidas dentro de una clase.

Voy a escribir un ejemplo rápido aquí en nuestra clase de mascotas para demostrarlo; creemos un método, llamado 'sleep', que imprimirá un mensaje cuando se llame por primera vez. Al igual que una función, voy a poner 'def' para 'definir', y luego voy a escribir el nombre del método que quiero crear. Luego vamos a poner nuestros paréntesis y punto y coma, y ​​luego comenzamos una nueva línea. Como de costumbre, todo lo incluido en este método se indentará un nivel adicional.

Ahora, hay otra diferencia entre un método y una función: un método siempre, siempre, siempre tiene que tener un argumento, llamado 'self' entre paréntesis. Cuando Python llama a un método, lo que hace es pasar el objeto actual a ese método como primer argumento. En otras palabras, cuando llamamos a doug.sleep (), Python realmente pasará el objeto 'doug' como argumento al método sleep.

Veremos por qué es más tarde, pero por ahora debe saber que, con un método, siempre debe incluir primero un argumento llamado "self" en la lista (si desea agregar más argumentos, puede agregarlos después, exactamente como si estuvieras pasando múltiples argumentos a una función). Si no incluyes ese argumento, cuando ejecutas el código, obtendrás un error porque Python está pasando un argumento (este objeto "self"), y el método está diciendo, 'Hola, hombre, No tomo ningún argumento, ¿de qué estás hablando? '. Es lo mismo que tratar de pasar un argumento a una función que no acepta ningún argumento.

Así que aquí está lo que tenemos hasta ahora:

Dentro de este método, vamos a escribir una declaración de impresión así:

Ahora, si queremos usar este método, simplemente usamos una instancia de la clase pet para referenciarlo. Al igual que la variable number_of_legs, escribimos el nombre de la instancia (tenemos una llamada doug), luego un punto, luego el nombre del método incluyendo los paréntesis. Tenga en cuenta que llamaremos a sleep sin argumentos, pero Python va a agregar ese argumento por sí mismo, por lo que vamos a terminar con la cantidad correcta de argumentos en total.

Si ejecuta este código, debería ver que imprime el mensaje que escribimos.

Datos

Genial, entonces ¿qué tal si escribimos un nuevo método para imprimir cuántas patas tiene la mascota, para demostrar cómo puede usar los métodos para comenzar a manipular los datos dentro de la clase y para demostrar por qué necesitamos incluir este confuso argumento "self". Vamos a hacer un nuevo método, llamado 'count_legs'.

Aquí es donde aparece el argumento 'self'. ¿Recuerdas cuando accedíamos a number_of_legs desde fuera de la clase y tuvimos que usar 'doug.number_of_legs' en lugar de solo 'number_of_legs'? El mismo principio aplica; si queremos saber qué está contenido en esa variable, debemos referenciarlo especificando primero la instancia que contiene esa variable.

Sin embargo, no sabemos cómo se llamará a la instancia cuando escribimos la clase, por lo que obtenemos el uso de la variable 'self'. 'self' es solo una referencia al objeto que está siendo manipulado actualmente. Por lo tanto, para acceder a una variable en la clase actual, simplemente debe introducirla con 'self' y luego con un punto, de esta manera:

En la práctica, lo que esto significa es que donde sea que escribas 'self' en tu método, cuando ejecutas el método ese self se reemplaza por el nombre del objeto, entonces cuando llamamos 'doug.count_legs ()' el 'self' es reemplazado por 'doug'. Para demostrar cómo funciona esto con varias instancias, agreguemos una segunda instancia, que representa a otra mascota, llamada 'nemo':

Esto imprimirá un mensaje para 4 y luego 0 patas, tal como queríamos, porque cuando llamamos 'nemo.count_legs (),' el 'self' es reemplazado por 'nemo' en lugar de 'doug'.

De esta forma, nuestro método se ejecutará exactamente como se pretende porque la referencia 'propia' cambiará dinámicamente según el contexto y nos permitirá manipular los datos solo dentro del objeto actual.

Lo principal que debe recordar sobre los métodos es que son exactamente como las funciones, excepto que el primer argumento tiene que ser "self" y que para hacer referencia a una variable interna debe preceder el nombre de la variable con "self".

Solo como una nota: en realidad puedes usar cualquier nombre en lugar de 'self' para tus métodos. --Los métodos aquí funcionarían igual de bien si cambiamos el nombre de la variable "self" a cualquier palabra. Usar el nombre 'self' es simplemente una convención que es útil para los programadores de Python porque hace que el código sea mucho más estándar y fácil de entender, incluso si es escrito por otra persona. Mi consejo sería mantener las convenciones.


Algunas características más avanzadas

Ahora que hemos analizado los conceptos básicos, echemos un vistazo a algunas características más avanzadas de las clases y cómo pueden ayudar a que su programación sea más fácil de estructurar.

Lo siguiente que vamos a hablar es sobre la herencia. Como su nombre podría indicar, la herencia es el proceso de crear una nueva clase basada en una clase padre y permitir que la nueva clase herede las características de la clase padre. La nueva clase puede tomar todos los métodos y variables de la clase padre (a menudo llamada la clase 'base').

La herencia es el proceso de hacer una nueva clase basada en una clase padre.

Extendamos nuestro ejemplo de pet para ver cómo esto podría ser útil. Si utilizamos 'pet' como nuestra clase padre, podríamos crear una clase hija la cual hereda de la clase pet. La clase hija podría ser algo así como "dog" o "fish"-- algo que sigue siendo una "pet", pero es más específico que eso. Un perro es una mascota y hace las mismas cosas que todas las mascotas-- por ejemplo, come y duerme, tiene una edad y un número patas-- pero tiene otras características específicas para ser un perro, o al menos más específico que ser una mascota: los perros tienen pelo, pero no todas las mascotas tienen. Un perro puede ladrar o buscar un palo, pero no todas las mascotas lo hacen.

Volviendo al punto, digamos que queríamos hacer una clase en nuestro programa para representar a un perro. Podríamos usar la herencia para heredar los métodos y las variables contenidas en 'pets' para que nuestro perro pueda tener un 'númeroDe piernas' y la capacidad de 'dormir', además de todas las cosas específicas que podríamos almacenar o hacer.

Ahora, ¿te estarás preguntando por qué no ponemos esos métodos y variables en la clase de perro y nos deshacemos completamente de la clase de mascota? Bueno, la herencia nos da dos ventajas distintas sobre ese enfoque: Una, si queremos un objeto que sea una mascota, pero no es un perro --una mascota genérica-- si se quiere, aún podemos hacerlo. Dos, quizás más tarde, queremos agregar un segundo tipo de mascota, tal vez un pez. Podemos hacer que esa segunda clase también herede de la mascota, por lo que ambas clases pueden compartir todo en la mascota, pero al mismo tiempo tienen sus propios métodos y variables más específicos que se aplican solo a ese tipo de objeto.

Aquí nos estamos atascando un poco en la teoría, así que vamos a escribir algo para aclararlo un poco. Primero, vamos a escribir una nueva clase, llamada 'dog', pero esta vez, entre el nombre de la clase y la coma, vamos a poner algunos paréntesis, y en ellos, vamos a escribir el nombre de la clase que queremos heredar, más o menos como si estuviéramos pasando esta nueva clase a un argumento, como si fuera una función.

A continuación, demos a esta clase un método simple para demostrar cómo funciona. Voy a agregar un método de 'bark' que imprimirá 'woof':

Entonces, ahora veamos qué sucede si hacemos una instancia de esta clase. Voy a llamar a nuestro nuevo perro 'doug' de nuevo. Ahora, si llamamos a doug.bark ():

Como se esperaba, doug ladra. Eso es genial, pero aún no hemos visto nada nuevo, solo una clase con un método. Lo que la herencia nos ha hecho, sin embargo, es hacer que todas las funciones y variables de las mascotas estén disponibles para nosotros a través de nuestro objeto 'doug', así que si hago algo como esto:

Entonces el método sleep también se ejecutará correctamente. En efecto, nuestro objeto doug pertenece tanto a la clase "pet" COMO a la clase "dog". Para garantizar que las variables hagan lo mismo que los métodos, intentemos esto:

Puedes ver que doug actúa exactamente como antes, mostrando que nuestras variables se heredan. Nuestra nueva clase hija es simplemente una versión especializada del padre, con alguna funcionalidad adicional pero que conserva todas las funcionalidades anteriores.


Así que ahí lo tienes, una introducción rápida a la programación orientada a objetos. Estén atentos para la próxima entrega de esta serie, ¡en la que trabajaremos con Python en la web!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.