¿Cuándo debo usar clases en Python?

He estado progtwigndo en python durante aproximadamente dos años; Principalmente datos (pandas, mpl, numpy), pero también scripts de automatización y pequeñas aplicaciones web. Estoy tratando de convertirme en un mejor progtwigdor y boost mi conocimiento de Python y una de las cosas que me molesta es que nunca he usado una clase (aparte de copiar código de matraz al azar para pequeñas aplicaciones web). Generalmente entiendo lo que son, pero parece que no puedo entender por qué los necesitaría con una función simple.

Para agregar especificidad a mi pregunta: escribo toneladas de informes automatizados que siempre involucran la extracción de datos de múltiples fonts de datos (mongo, sql, postgres, apis), realizando una gran cantidad de datos y formándolos, escribiéndolos en csv / excel / html, enviarlo en un correo electrónico. Los scripts van desde ~ 250 líneas hasta ~ 600 líneas. ¿Habría alguna razón para que yo usara clases para hacer esto y por qué?

Las clases son el stackr de la progtwigción orientada a objetos . La progtwigción orientada a objetos está muy relacionada con la organización del código, la reutilización y la encapsulación.

Primero, un descargo de responsabilidad: la progtwigción orientada a objetos (OOP) contrasta parcialmente con la progtwigción funcional , que es un paradigma diferente que se usa mucho en Python. No todos los que progtwign en Python (o seguramente la mayoría de los idiomas) usan OOP. Puedes hacer mucho en Java 8 que no está muy orientado a objetos. Si no quieres usar OOP, entonces no lo hagas. Si solo está escribiendo scripts únicos para procesar datos que nunca volverá a usar, siga escribiendo de la forma en que lo está.

Sin embargo, hay muchas razones para usar OOP.

Algunas razones:

  • Organización: OOP define formas bien conocidas y estándar de describir y definir tanto los datos como los procedimientos en el código. Tanto los datos como el procedimiento se pueden almacenar en diferentes niveles de definición (en diferentes clases), y hay formas estándar de hablar sobre estas definiciones. Es decir, si usa la POO de una manera estándar, ayudará a su yo posterior y a los demás a entender, editar y usar su código. Además, en lugar de utilizar un mecanismo de almacenamiento de datos complejo y arbitrario (dicts de dicts o listas o dicts o listas de dicts de conjuntos, o lo que sea), puede nombrar partes de estructuras de datos y consultarlas convenientemente.

  • Estado: la progtwigción orientada a objetos te ayuda a definir y realizar un seguimiento del estado. Por ejemplo, en un ejemplo clásico, si está creando un progtwig que procesa a los estudiantes (por ejemplo, un progtwig de calificación), puede mantener toda la información que necesita sobre ellos en un solo lugar (nombre, edad, sexo, nivel de grado, cursos, calificaciones, profesores, compañeros, dieta, necesidades especiales, etc.), y estos datos se conservan siempre que el objeto esté vivo y sea fácilmente accesible.

  • Encapsulación : con encapsulación, el procedimiento y los datos se almacenan juntos. Los métodos (un término OOP para funciones) se definen junto con los datos que operan y producen. En un lenguaje como Java que permite el control de acceso , o en Python, dependiendo de cómo describa su API pública, esto significa que los métodos y los datos pueden ocultarse al usuario. Lo que esto significa es que si necesita o desea cambiar el código, puede hacer lo que quiera para la implementación del código, pero mantener las API públicas iguales.

  • Herencia : la herencia le permite definir datos y procedimientos en un lugar (en una clase), y luego anular o ampliar esa funcionalidad más adelante. Por ejemplo, en Python, a menudo veo personas que crean subclases de la clase dict para agregar funcionalidad adicional. Un cambio común es anular el método que lanza una excepción cuando se solicita una clave de un diccionario que no existe para dar un valor predeterminado basado en una clave desconocida. Esto le permite extender su propio código ahora o más adelante, permite que otros amplíen su código y le permite extender el código de otras personas.

  • Reutilización: Todas estas razones y otras permiten una mayor reutilización del código. El código orientado a objetos le permite escribir código sólido (probado) una vez, y luego reutilizarlo una y otra vez. Si necesita modificar algo para su caso de uso específico, puede heredar de una clase existente y sobrescribir el comportamiento existente. Si necesita cambiar algo, puede cambiarlo todo a la vez que mantiene las firmas de métodos públicos existentes, y nadie es más sabio (con suerte).

Nuevamente, hay varias razones para no usar OOP, y no es necesario. Pero afortunadamente con un lenguaje como Python, puedes usar solo un poco o mucho, depende de ti.

Un ejemplo del caso de uso del estudiante (no hay garantía sobre la calidad del código, solo un ejemplo):

Orientado a objetos

 class Student(object): def __init__(self, name, age, gender, level, grades=None): self.name = name self.age = age self.gender = gender self.level = level self.grades = grades or {} def setGrade(self, course, grade): self.grades[course] = grade def getGrade(self, course): return self.grades[course] def getGPA(self): return sum(self.grades.values())/len(self.grades) # Define some students john = Student("John", 12, "male", 6, {"math":3.3}) jane = Student("Jane", 12, "female", 6, {"math":3.5}) # Now we can get to the grades easily print(john.getGPA()) print(jane.getGPA()) 

Dictado estándar

 def calculateGPA(gradeDict): return sum(gradeDict.values())/len(gradeDict) students = {} # We can set the keys to variables so we might minimize typos name, age, gender, level, grades = "name", "age", "gender", "level", "grades" john, jane = "john", "jane" math = "math" students[john] = {} students[john][age] = 12 students[john][gender] = "male" students[john][level] = 6 students[john][grades] = {math:3.3} students[jane] = {} students[jane][age] = 12 students[jane][gender] = "female" students[jane][level] = 6 students[jane][grades] = {math:3.5} # At this point, we need to remember who the students are and where the grades are stored. Not a huge deal, but avoided by OOP. print(calculateGPA(students[john][grades])) print(calculateGPA(students[jane][grades])) 

Siempre que necesite mantener un estado de sus funciones y no se puede lograr con generadores (funciones que rinden en lugar de regresar). Los generadores mantienen su propio estado.

Si desea anular cualquiera de los operadores estándar , necesita una clase.

Siempre que tenga un uso para un patrón de Visitante, necesitará clases. Cualquier otro patrón de diseño se puede lograr de manera más efectiva y limpia con generadores, administradores de contexto (que también se implementan mejor como generadores que como clases) y tipos de POD (diccionarios, listas y tuplas, etc.).

Si desea escribir código “pythonic”, debería preferir los gestores de contexto y los generadores en lugar de las clases. Será más limpio.

Si desea ampliar la funcionalidad, casi siempre podrá realizarla con contención en lugar de con herencia.

Como toda regla, esto tiene una excepción. Si desea encapsular la funcionalidad rápidamente (es decir, escribir código de prueba en lugar de código reutilizable a nivel de biblioteca), puede encapsular el estado en una clase. Será simple y no tendrá que ser reutilizable.

Si necesita un destructor de estilo C ++ (RIIA), definitivamente NO desea usar clases. Quieres gestores de contexto.

Creo que lo haces bien. Las clases son razonables cuando necesita simular una lógica de negocios o procesos difíciles de la vida real con relaciones difíciles. Como ejemplo:

  • Varias funciones con estado compartido.
  • Más de una copia de las mismas variables de estado.
  • Ampliar el comportamiento de una funcionalidad existente.

También te sugiero que veas este clásico video.

Una clase define una entidad del mundo real. Si está trabajando en algo que existe individualmente y tiene su propia lógica que está separada de los demás, debe crear una clase para ello. Por ejemplo, una clase que encapsula conectividad de base de datos.

Si este no es el caso, no es necesario crear clase.

Depende de tu idea y diseño. Si usted es un buen diseñador, los OOP saldrán naturalmente en forma de varios patrones de diseño. Para un simple procesamiento de nivel de script, los OOP pueden ser una sobrecarga. Simplemente considere los beneficios básicos de los OOP como reutilizables y extensibles y asegúrese de que sean necesarios o no. Los OOP hacen que las cosas complejas sean más simples y las cosas más complejas. Simplemente mantiene las cosas simples de cualquier manera utilizando OOP o no utilizando OOP. lo que sea más sencillo es usar eso.