ProgramaciónDesarrollador Python middle/senior

Hable sobre el trabajo y la aplicación de las funciones partial y partialmethod del módulo functools. ¿Cuál es la diferencia entre ellas, por qué aplicarlas en el diseño del código y cuáles son sus características?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia de la pregunta

La función partial apareció en la biblioteca estándar de Python (módulo functools), a partir de Python 2.5, para implementar el patrón de currying y la aplicación parcial de argumentos a una función. La función partialmethod apareció con Python 3.4 para un uso similar en métodos de clases.

Problema

A menudo, en proyectos reales, surge la necesidad de fijar parte de los argumentos en una función para obtener una nueva función con valores "recordados" de algunos argumentos. Esto es conveniente para callbacks, plantillas de paso de argumentos, o para aumentar la legibilidad del código, especialmente en programación funcional y al usar API que esperan un estilo particular de funciones.

Solución

La función partial devuelve un nuevo objeto-función, en la que algunos de los argumentos o argumentos clave pasados están "fijados". La función partialmethod implementa el mismo enfoque para los métodos de clases, admitiendo correctamente la mecánica de paso de self/cls.

Ejemplo de código:

from functools import partial, partialmethod def power(base, exponent): return base ** exponent # Fijamos el exponente = 2 square = partial(power, exponent=2) print(square(5)) # 25 class Math: def power(self, base, exponent): return base ** exponent square = partialmethod(power, exponent=2) m = Math() print(m.square(5)) # 25

Características clave:

  • partial crea una nueva función con valores parte de los argumentos fijados.
  • partialmethod es una construcción similar para métodos de clases, que trabaja correctamente con self/cls.
  • Aumentan la legibilidad, permiten crear "envolturas funcionales" y callbacks con parámetros fijados.

Preguntas engañosas.

¿Se puede usar partial para métodos de clase para obtener un equivalente a partialmethod?

No, partial no maneja self/cls correctamente, al aplicarlo a un método de clase no funcionará como se espera: self no se asignará automáticamente.

class C: def m(self, x, y): return x + y wrong = partial(m, y=2) # ¡Incorrecto!

Al llamar c.wrong(5) se producirá un TypeError, porque self no se pasará automáticamente.

¿El objeto creado a través de partial es una función?

Sí, el resultado de partial es un objeto que se comporta como una función, admite llamada, nombre, docstring, etc., pero no es una función normal, es un objeto de la clase partial, que implementa el protocolo call.

from functools import partial f = partial(pow, 2) print(type(f)) # <class 'functools.partial'>

¿Funciona partial con los argumentos por defecto de una función?

Sí, partial puede "sobrescribir" los valores por defecto en la función interna; si se pasan argumentos a partial, tienen prioridad sobre los valores por defecto en la propia función. Sin embargo, es importante no duplicar valores, de lo contrario habrá un error.

Errores típicos y antipatrones

  • Aplicar partial a métodos vinculados, esperando obtener un self correcto — no funciona, hay que usar partialmethod.
  • Pasar valores de argumentos fijados demasiado tarde o incorrectos — generará un error al momento de la llamada.
  • Complicar la estructura del código, abusando de partial para funciones triviales.

Ejemplo de la vida real

Caso negativo

El desarrollador aplica partial para un método de clase en lugar de partialmethod:

class MyClass: def f(self, x, y): ... squared = partial(f, y=2) ... obj = MyClass() obj.squared(5) # TypeError: missing 1 required positional argument: 'self'

Pros:

  • El código se ve conciso.

Contras:

  • No funciona la "magia" de pasar self.
  • El error aparece solo en tiempo de ejecución.

Caso positivo

En su lugar se aplica partialmethod:

from functools import partialmethod class MyClass: def f(self, x, y): return x + y squared = partialmethod(f, y=2) obj = MyClass() print(obj.squared(5)) # 7

Pros:

  • Funciona como se espera.
  • Código legible y escalable.

Contras:

  • Requiere conocer las capacidades de partialmethod (no para principiantes).