Menu
Coddy logo textTech

Repaso - Lista personalizada

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

challenge icon

Desafío

Intermedio

En este desafío, implementarás una clase CustomList completamente funcional que imita el comportamiento de las listas integradas de Python, mientras demuestras tu comprensión de los métodos especiales.

Edita solo el archivo customlist.py siguiendo los comentarios TODO que guían tu implementación paso a paso.

Tu implementación debe admitir:

  • Inicialización con elementos opcionales
  • Indexación (obtener/establecer valores)
  • Verificación de longitud con len()
  • Suma con otras listas
  • Representación de cadena
  • Iteración y comprobaciones de pertenencia
  • Métodos: append, pop, y clear

Hoja de referencia

Una clase CustomList puede implementarse utilizando métodos especiales (métodos dunder) para imitar el comportamiento de las listas integradas de Python:

  • __init__(self, items=None) - Inicializar con elementos opcionales
  • __getitem__(self, index) - Habilitar la indexación para obtener valores
  • __setitem__(self, index, value) - Habilitar la indexación para establecer valores
  • __len__(self) - Habilitar la función len()
  • __add__(self, other) - Habilitar la suma con otras listas
  • __str__(self) - Representación de cadena
  • __iter__(self) - Habilitar la iteración
  • __contains__(self, item) - Habilitar el operador in

Métodos de lista comunes para implementar:

  • append(self, item) - Agregar un elemento al final
  • pop(self, index=-1) - Eliminar y devolver el elemento en el índice
  • clear(self) - Eliminar todos los elementos

Pruébalo tú mismo

from customlist import CustomList


def test_basic_functionality():
    """Prueba la funcionalidad básica de CustomList"""
    try:
        # Probar inicialización
        empty_list = CustomList()
        assert len(empty_list) == 0, f"Empty list should have length 0, but has {len(empty_list)}"
        
        init_list = CustomList([1, 2, 3])
        assert len(init_list) == 3, f"Initialized list should have length 3, but has {len(init_list)}"
        
        # Probar indexación
        assert init_list[0] == 1, f"First element should be 1, but got {init_list[0]}"
        init_list[1] = 10
        assert init_list[1] == 10, f"Element after assignment should be 10, but got {init_list[1]}"
        
        # Probar representación de cadena
        assert str(init_list) == "[1, 10, 3]", f"String representation incorrect, got {str(init_list)}"
        
        # Probar adición
        combined = init_list + CustomList([4, 5])
        assert len(combined) == 5, f"Combined list should have length 5, but has {len(combined)}"
        assert combined[3] == 4, f"Fourth element of combined list should be 4, but got {combined[3]}"
        
        # Probar iteración y pertenencia
        items = []
        for item in combined:
            items.append(item)
        assert items == [1, 10, 3, 4, 5], f"Iteration produced incorrect items: {items}"
        
        assert 10 in combined, "10 should be in the list"
        assert 7 not in combined, "7 should not be in the list"
        
        # Probar append y pop
        combined.append(6)
        assert len(combined) == 6, f"After append, length should be 6, but got {len(combined)}"
        assert combined[5] == 6, f"Last element after append should be 6, but got {combined[5]}"
        
        popped = combined.pop()
        assert popped == 6, f"Popped value should be 6, but got {popped}"
        assert len(combined) == 5, f"After pop, length should be 5, but got {len(combined)}"
        
        # Probar clear
        combined.clear()
        assert len(combined) == 0, f"After clear, length should be 0, but got {len(combined)}"
        
        print("Basic functionality tests passed!")
        return True
    except Exception as e:
        print(f"Basic functionality test failed: {e}")
        return False


def test_edge_cases():
    """Prueba casos límite y condiciones de borde"""
    try:
        # Probar con operaciones de lista vacía
        empty_list = CustomList()
        
        # Probar pop en lista vacía
        try:
            empty_list.pop()
            assert False, "pop() on empty list should raise IndexError"
        except IndexError:
            pass  # Comportamiento esperado
        
        # Probar indexación en lista vacía
        try:
            value = empty_list[0]
            assert False, "Indexing empty list should raise IndexError"
        except IndexError:
            pass  # Comportamiento esperado
            
        # Probar con valores None
        none_list = CustomList([None, None])
        assert len(none_list) == 2, f"List with None values should have length 2, got {len(none_list)}"
        assert none_list[0] is None, "First element should be None"
        
        # Probar con tipos mixtos
        mixed_list = CustomList([1, "string", 3.14, [1, 2], {"key": "value"}])
        assert len(mixed_list) == 5, f"Mixed type list should have length 5, got {len(mixed_list)}"
        assert mixed_list[1] == "string", f"Second element should be 'string', got {mixed_list[1]}"
        
        # Probar adición con lista regular
        result = mixed_list + [6, 7, 8]
        assert len(result) == 8, f"After adding regular list, length should be 8, got {len(result)}"
        assert result[5] == 6, f"Sixth element should be 6, got {result[5]}"
        
        # Probar adición con lista vacía
        result = mixed_list + []
        assert len(result) == 5, f"After adding empty list, length should be 5, got {len(result)}"
        assert result[0] == 1, f"First element should still be 1, got {result[0]}"
        
        # Probar repr
        repr_str = repr(CustomList([1, 2, 3]))
        assert repr_str == "CustomList([1, 2, 3])", f"repr should be 'CustomList([1, 2, 3])', got {repr_str}"
        
        print("Edge case tests passed!")
        return True
    except Exception as e:
        print(f"Edge case test failed: {e}")
        return False


def test_large_lists():
    """Prueba el rendimiento con listas grandes"""
    try:
        # Crear y probar operaciones en listas grandes
        # Crear una lista grande
        large_list = CustomList(range(10000))
        assert len(large_list) == 10000, f"Large list should have length 10000, got {len(large_list)}"
        
        # Probar indexación en lista grande
        assert large_list[9999] == 9999, f"Last element should be 9999, got {large_list[9999]}"
        
        # Probar pertenencia en lista grande
        assert 5000 in large_list, "5000 should be in the large list"
        assert 10001 not in large_list, "10001 should not be in the large list"
        
        # Probar adición de dos listas grandes
        other_large = CustomList(range(10000, 20000))
        combined = large_list + other_large
        assert len(combined) == 20000, f"Combined large lists should have length 20000, got {len(combined)}"
        assert combined[0] == 0, f"First element should be 0, got {combined[0]}"
        assert combined[19999] == 19999, f"Last element should be 19999, got {combined[19999]}"
        
        print("Large list tests passed!")
        return True
    except Exception as e:
        print(f"Large list test failed: {e}")
        return False


def test_nested_lists():
    """Prueba con objetos CustomList anidados"""
    try:
        # Probar objetos CustomList anidados
        inner1 = CustomList([1, 2, 3])
        inner2 = CustomList([4, 5, 6])
        outer = CustomList([inner1, inner2, 7])
        
        assert len(outer) == 3, f"Outer list should have length 3, got {len(outer)}"
        assert outer[0] is inner1, "First element should be inner1"
        assert len(outer[0]) == 3, f"First inner list should have length 3, got {len(outer[0])}"
        assert outer[0][1] == 2, f"Second element of first inner list should be 2, got {outer[0][1]}"
        
        # Probar la modificación de la lista interna
        inner1.append(4)
        assert len(outer[0]) == 4, f"After append, inner list should have length 4, got {len(outer[0])}"
        assert outer[0][3] == 4, f"Fourth element of inner list should be 4, got {outer[0][3]}"
        
        # Probar adición anidada
        result = outer[0] + outer[1]
        assert len(result) == 7, f"Combined inner lists should have length 7, got {len(result)}"
        assert result[0] == 1, f"First element should be 1, got {result[0]}"
        assert result[6] == 6, f"Last element should be 6, got {result[6]}"
        
        print("Nested list tests passed!")
        return True
    except Exception as e:
        print(f"Nested list test failed: {e}")
        return False


def test_custom_operations():
    """Prueba operaciones personalizadas y combinaciones"""
    try:
        # Probar operaciones personalizadas y combinaciones de métodos
        # Probar operaciones encadenadas
        list1 = CustomList([1, 2])
        list2 = CustomList([3, 4])
        list3 = CustomList([5, 6])
        
        # Adiciones en cadena
        result = list1 + list2 + list3
        assert len(result) == 6, f"Chained addition should have length 6, got {len(result)}"
        assert result[5] == 6, f"Last element should be 6, got {result[5]}"
        
        # Probar secuencia de append y pop
        test_list = CustomList([1, 2, 3])
        test_list.append(4)
        test_list.append(5)
        assert test_list.pop() == 5, "First pop should return 5"
        assert test_list.pop() == 4, "Second pop should return 4"
        assert len(test_list) == 3, f"After two pops, length should be 3, got {len(test_list)}"
        
        # Probar clear y luego append
        test_list.clear()
        assert len(test_list) == 0, f"After clear, length should be 0, got {len(test_list)}"
        test_list.append(10)
        assert len(test_list) == 1, f"After append to cleared list, length should be 1, got {len(test_list)}"
        assert test_list[0] == 10, f"Element should be 10, got {test_list[0]}"
        
        # Probar adición de listas vacías
        empty1 = CustomList()
        empty2 = CustomList()
        empty_sum = empty1 + empty2
        assert len(empty_sum) == 0, f"Sum of empty lists should be empty, got length {len(empty_sum)}"
        
        print("Custom operations tests passed!")
        return True
    except Exception as e:
        print(f"Custom operations test failed: {e}")
        return False


# Ejecutar la prueba seleccionada o todas las pruebas
test_case = input()

if test_case == "basic":
    test_basic_functionality()
elif test_case == "edge":
    test_edge_cases()
elif test_case == "large":
    test_large_lists()
elif test_case == "nested":
    test_nested_lists()
elif test_case == "custom":
    test_custom_operations()
else:
    print("Invalid test case. Running basic tests by default.")
    test_basic_functionality()

Todas las lecciones de Object Oriented Programming