Las Classes combinan datos con comportamiento.
Las clases se usan para crear copias o instances de datos y comportamiento agrupados, conocidos comúnmente como objects.
Los objetos pueden representar entidades del mundo real (como coches o gatos) o conceptos más abstractos (como números enteros, vehículos o mamíferos).
Las clases son fundamentales para un enfoque de programación orientada a objetos (POO), que pide al programador que piense en modelar un problema como uno o más objetos que interactúan entre sí, mantienen un estado y actúan sobre los datos.
Las clases son las definiciones de nuevos tipos de objeto, y a partir de ellas se crean nuevos instances de objetos.
A menudo agrupan datos (conocidos como fields, attributes, properties, data members o variables) junto con código o funciones (conocidas como methods) que operan sobre esos datos.
En este sentido, una clase es un plano o un conjunto de instrucciones a partir del cual se pueden construir y usar muchos objetos de un tipo similar.
Un programa complejo puede tener muchas clases, y cada una construye muchas variedades distintas de objetos.
El proceso de construir y personalizar un objeto a partir de una clase se conoce como instantiation (o crear una instancia de la clase).
La definición de una clase en Python es sencilla:
class MyClass:
# Class body goes here
Los campos de clase (también conocidos como propiedades, atributos, miembros de datos o variables) se pueden añadir al cuerpo de la clase.
class MyClass:
number = 5
string = "Hello!"
Se puede crear una instancia (objeto) de MyClass y vincularla a un nombre:
>>> new_object = MyClass()
# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>
Los Class attributes se comparten entre todos los objetos (o instancias) creados a partir de una clase, y se puede acceder a ellos mediante la dot notation: un . colocado después del nombre del objeto y antes del nombre del atributo:
>>> new_object = MyClass()
# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5
# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'
# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()
>>> second_new_object
<__main__.MyClass at 0x15ad99970>
# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True
Los atributos de clase se definen en el cuerpo de la propia clase, antes que cualquier otro método. Son propiedad de la clase, lo que permite compartirlos entre las instancias. Como estos atributos los comparten todas las instancias de la clase, se puede acceder a su valor y manipularlo directamente desde la clase. Alterar el valor de los atributos de clase altera el valor para todos los objetos instanciados a partir de la clase:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
# Accessing a class attribute from an object.
>>> obj_two.number
5
# Accessing the class attribute from the class itself.
>>> MyClass.number
5
# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27
# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27
>>> obj_two.number
27
Tener un montón de objetos con datos sincronizados en todo momento no es especialmente útil.
Por suerte, los objetos creados a partir de una clase se pueden personalizar con sus propios instance attributes (o propiedades, variables o campos de instancia).
Como su nombre indica, los atributos de instancia son únicos para cada objeto y se pueden modificar de forma independiente.
__init__()
El «método dunder» especial (abreviatura de «método de doble guion bajo»), __init__(), se usa para personalizar las instancias de una clase y permite inicializar los atributos o propiedades de instancia de los objetos.
Por su papel a la hora de inicializar los atributos de instancia, a __init__() también se le llama class constructor o initializer.
__init__() recibe un parámetro obligatorio llamado self, que hace referencia al objeto recién iniciado o creado.
A continuación, se pueden pasar datos para los atributos o propiedades de instancia como argumentos de __init__(), después del parámetro self.
Más abajo, MyClass tiene ahora atributos de instancia llamados location_x y location_y.
Como puedes ver, los dos atributos se han asignado al primer y segundo índice del argumento location (una tupla) que se ha pasado a __init__().
Los atributos location_x y location_y de una instancia de la clase se inicializarán ahora cuando crees una instancia de la clase y se cree un objeto:
class MyClass:
# These are class attributes, variables, or fields.
number = 5
string = "Hello!"
# This is the class "constructor", with a "location" parameter that is a tuple.
def __init__(self, location):
# This is an instance or object property, attribute, or variable.
# Note that we are unpacking the tuple argument into two separate instance variables.
self.location_x = location[0]
self.location_y = location[1]
# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))
# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))
# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1
>>> new_object_two.location_x
-8
Ten en cuenta que solo necesitas pasar un argumento al inicializar MyClass arriba: Python se encarga de pasar self cuando se llama a la clase.
Otra forma de crear una variable de instancia es simplemente acceder a una variable de clase a través de un objeto y cambiarla por otra cosa:
>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'
>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'
>>> obj_one.string
'Hello!'
Ahora, observa qué ocurre cuando cambia la variable de clase:
>>> MyClass.string = "World!"
>>> obj_two.string
# obj_two.string has not changed
'Hi!'
>>> obj_one.string
# obj_one.string changed
'World!'
El atributo string es ahora una variable de instancia en el caso de obj_two, pero sigue siendo una variable de clase en obj_one.
Esto también se puede hacer desde dentro de la clase:
class Demo:
new_var = 3
def add_two(self):
self.new_var += 2
En el momento en que se llama a <object>.add_two() y se lee self.new_var += 2, new_var pasa de ser una variable de clase a una variable de instancia del mismo nombre.
Esto puede resultar útil durante la inicialización, cuando todas las instancias de una clase necesitan que algún atributo empiece con el mismo valor.
Sin embargo, la variable de instancia oculta entonces la variable de clase, lo que hace que esta sea inaccesible desde la instancia en la que queda oculta.
Dada esta situación, puede ser más seguro y más claro establecer los atributos de instancia desde el método __init__() como self.<attribute>.
Un method es una function vinculada a la propia clase (conocida como método de clase, que se tratará en profundidad en un ejercicio posterior) o a una instancia de la clase (objeto).
Los métodos que operan sobre un objeto o una instancia deben definirse con self como primer parámetro.
Después puedes definir el resto de los parámetros como lo harías en una función «normal» o no vinculada.
Los métodos que operan sobre una clase deben definirse con el decorador @classmethod y (por convención) con cls como primer parámetro.
A los métodos de clase se les llama directamente sobre una clase, sin crear antes un objeto a partir de ella.
class MyClass:
number = 5
string = "Hello!"
# Class constructor.
def __init__(self, location):
# Instance properties
self.location_x = location[0]
self.location_y = location[1]
# Class method. Uses the @classmethod decorator, and cls as the first parameter.
# Can be called without first making an instance of the class.
@classmethod
def change_string(cls, new_string):
#Class attributes are referred to with cls.
cls.string = new_string
return cls.string
# Instance method. Note "self" as first parameter.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
Igual que para acceder a un atributo, llamar a un método es tan sencillo como poner un . después del nombre del objeto y antes del nombre del método.
El método llamado no necesita una copia del objeto como primer parámetro: Python rellena self automáticamente:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)
# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)
Se puede acceder a los atributos de clase desde dentro de los métodos de instancia de la misma forma que se accede a ellos desde fuera de la clase:
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances from within an instance.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5
>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6
pass
En los ejercicios de concepto anteriores y en los esqueletos de ejercicios de práctica, habrás visto la palabra clave pass dentro del cuerpo de las funciones en lugar del código real.
La palabra clave pass es un marcador de posición sintácticamente válido: evita que Python lance un error de sintaxis por una función o una definición de clase vacía.
Básicamente, es una forma de decirle al intérprete de Python: «¡No te preocupes! Voy a poner código aquí con el tiempo, simplemente aún no lo he hecho».
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
# This will compile and run without error, but has no current functionality.
def pending_functionality(self):
# Stubbing or place-holding the body of this method.
pass