Menu
Coddy logo textTech

Métodos estáticos y de clase

Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 39 de 64.

Además de los métodos de instancia regulares, las clases pueden tener métodos estáticos y métodos de clase que sirven para diferentes propósitos.

Aquí tienes un ejemplo de un método estático:

class MathHelper:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def is_even(number):
        return number % 2 == 0

Los métodos estáticos no necesitan self y funcionan como funciones regulares. Llámalos directamente desde la clase:

result = MathHelper.add(5, 3)
print(result)

check = MathHelper.is_even(10)
print(check)

Aquí hay un ejemplo de un método de clase:

class Person:
    count = 0  # Variable de clase
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count
    
    @classmethod
    def create_anonymous(cls):
        return cls("Anonymous")

Los métodos de clase reciben la clase misma (cls) como el primer parámetro:

person1 = Person("Alice")
person2 = Person("Bob")
print(Person.get_count())  # 2

Usa métodos de clase como constructores alternativos:

anonymous = Person.create_anonymous()
print(anonymous.name)      # Anonymous
print(Person.get_count())  # 3

Compara los tres tipos de métodos en una sola clase:

class Calculator:
    brand = "Python Calc"
    
    def __init__(self, owner):
        self.owner = owner
    
    # Método de instancia - necesita self, accede a los datos de la instancia
    def show_owner(self):
        return f"Owned by {self.owner}"
    
    # Método de clase - necesita cls, accede a los datos de la clase
    @classmethod
    def get_brand(cls):
        return cls.brand
    
    # Método estático - no necesita ninguno de los dos, es solo una función de utilidad
    @staticmethod
    def multiply(x, y):
        return x * y
calc = Calculator("Alice")
print(calc.show_owner())        # Propiedad de Alice
print(Calculator.get_brand())   # Python Calc
print(Calculator.multiply(4, 5)) # 20

Salida:

8
True
2
Anonymous
3
Owned by Alice
Python Calc
20

También puedes llamar a métodos de clase y estáticos desde las instancias:

calc = Calculator("Bob")
print(calc.get_brand())      # Python Calc
print(calc.multiply(2, 3))   # 6

Diferencias clave:

  • Métodos de instancia: Necesitan self, acceden a los datos de la instancia
  • Métodos de clase: Necesitan cls, acceden a los datos de la clase, son útiles para constructores alternativos
  • Métodos estáticos: No necesitan ninguno de los dos, son simplemente funciones de utilidad relacionadas con la clase

Punto clave: Usa @staticmethod para funciones de utilidad que pertenecen lógicamente a la clase pero no necesitan datos de la clase o de la instancia. Usa @classmethod cuando necesites acceso a la clase en sí, como para constructores alternativos o para acceder a variables de clase.

challenge icon

Desafío

Fácil

En este desafío, implementarás una clase Temperature con una funcionalidad específica mientras aprovechas un marco de pruebas exhaustivo.

Debes editar solo el archivo temperature.py, siguiendo los comentarios TODO que guían tu implementación. La clase debe incluir:

  • Una variable de clase para rastrear las lecturas de temperatura
  • Un método estático para la conversión de temperatura
  • Métodos de clase para agregar lecturas y calcular promedios

Hoja de referencia

Las clases pueden tener tres tipos de métodos: métodos de instancia, métodos estáticos y métodos de clase.

Los métodos estáticos usan el decorador @staticmethod, no necesitan self y funcionan como funciones regulares:

class MathHelper:
    @staticmethod
    def add(a, b):
        return a + b

# Call directly from class
result = MathHelper.add(5, 3)

Los métodos de clase usan el decorador @classmethod y reciben la clase (cls) como primer parámetro:

class Person:
    count = 0
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count
    
    @classmethod
    def create_anonymous(cls):
        return cls("Anonymous")

# Usage
print(Person.get_count())
anonymous = Person.create_anonymous()

Diferencias clave:

  • Métodos de instancia: Necesitan self, acceden a los datos de la instancia
  • Métodos de clase: Necesitan cls, acceden a los datos de la clase, son útiles para constructores alternativos
  • Métodos estáticos: No necesitan ninguno de los dos, son solo funciones de utilidad relacionadas con la clase

Tanto los métodos de clase como los estáticos pueden llamarse desde la clase o desde las instancias:

Calculator.multiply(4, 5)  # Desde la clase
calc.multiply(4, 5)        # Desde la instancia

Pruébalo tú mismo

from temperature import Temperature

# Manejador de casos de prueba para pruebas exhaustivas
test_case = input()

if test_case == "default_test":
    # Probar funcionalidad básica
    Temperature.celsius_readings = []
    Temperature.add_reading(25)
    Temperature.add_reading(30)
    Temperature.add_reading(27)
    
    print(f"Average reading: {Temperature.average_reading()}")
    print(f"22°C is {Temperature.celsius_to_fahrenheit(22)}°F")

elif test_case == "empty_readings":
    # Probar average_reading sin lecturas
    Temperature.celsius_readings = []
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "single_reading":
    # Probar con una sola lectura
    Temperature.celsius_readings = []
    Temperature.add_reading(100)
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "negative_values":
    # Probar con valores de temperatura negativos
    Temperature.celsius_readings = []
    Temperature.add_reading(-10)
    Temperature.add_reading(-20)
    Temperature.add_reading(-30)
    print(f"Average reading: {Temperature.average_reading()}")
    print(f"-15°C is {Temperature.celsius_to_fahrenheit(-15)}°F")

elif test_case == "zero_value":
    # Probar con una lectura de 0°C
    print(f"0°C is {Temperature.celsius_to_fahrenheit(0)}°F")

elif test_case == "extreme_values":
    # Probar con valores de temperatura extremos
    absolute_zero = -273.15  # cero absoluto en Celsius
    sun_surface = 5500  # temperatura aproximada de la superficie del sol en Celsius
    
    print(f"{absolute_zero}°C is {Temperature.celsius_to_fahrenheit(absolute_zero)}°F")
    print(f"{sun_surface}°C is {Temperature.celsius_to_fahrenheit(sun_surface)}°F")

elif test_case == "reset_readings":
    # Probar el reinicio de las lecturas
    Temperature.celsius_readings = []
    Temperature.add_reading(10)
    Temperature.add_reading(20)
    Temperature.add_reading(30)
    print(f"Average reading before reset: {Temperature.average_reading()}")
    
    Temperature.celsius_readings = []
    print(f"Average reading after reset: {Temperature.average_reading()}")

elif test_case == "decimal_values":
    # Probar con valores decimales
    Temperature.celsius_readings = []
    Temperature.add_reading(36.5)  # Temperatura corporal normal
    Temperature.add_reading(37.2)  # Fiebre leve
    Temperature.add_reading(36.9)  # Variación normal
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "many_readings":
    # Probar con muchas lecturas
    Temperature.celsius_readings = []
    for i in range(1, 101):
        Temperature.add_reading(i)
    print(f"Average reading with 100 values: {Temperature.average_reading()}")
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming