Me estoy enseñando Python y mi lección más reciente fue que Python no es Java , por lo que acabo de pasar un tiempo convirtiendo todos mis métodos de Class en funciones.
Ahora me doy cuenta de que no necesito usar métodos Class para lo que haría con los static
métodos en Java, pero ahora no estoy seguro de cuándo los usaría. Todos los consejos que puedo encontrar sobre los métodos de Python Class están en la línea de que los novatos como yo deberían evitarlos, y la documentación estándar es más opaca cuando se discute sobre ellos.
¿Alguien tiene un buen ejemplo de uso de un método de Clase en Python o al menos alguien me puede decir cuándo los métodos de Clase se pueden usar con sensatez?
fuente
obj.cls_mthd(...)
otype(obj).cls_mthd(...)
?Los métodos de fábrica (constructores alternativos) son de hecho un ejemplo clásico de métodos de clase.
Básicamente, los métodos de clase son adecuados en cualquier momento que desee tener un método que se ajuste naturalmente al espacio de nombres de la clase, pero que no esté asociado con una instancia particular de la clase.
Como ejemplo, en el excelente módulo unipath :
Directorio actual
Path.cwd()
Path("/tmp/my_temp_dir")
. Este es un método de clase..chdir()
Como el directorio actual abarca todo el proceso, el
cwd
método no tiene una instancia particular con la que deba asociarse. Sin embargo, cambiar elcwd
directorio al directorio de unaPath
instancia dada debería ser un método de instancia.Hmmm ... como de
Path.cwd()
hecho devuelve unaPath
instancia, supongo que podría considerarse un método de fábrica ...fuente
Piénselo de esta manera: los métodos normales son útiles para ocultar los detalles del despacho: puede escribir
myobj.foo()
sin preocuparse de si elfoo()
método es implementado por lamyobj
clase del objeto o una de sus clases principales. Los métodos de clase son exactamente análogos a esto, pero con el objeto de clase en su lugar: le permiten llamarMyClass.foo()
sin tener que preocuparse de sifoo()
se implementa especialmenteMyClass
porque necesitaba su propia versión especializada, o si está permitiendo que su clase padre maneje la llamada.Los métodos de clase son esenciales cuando realiza una configuración o cálculo que precede a la creación de una instancia real, porque hasta que la instancia exista, obviamente no puede usar la instancia como punto de envío para sus llamadas a métodos. Un buen ejemplo se puede ver en el código fuente de SQLAlchemy; Eche un vistazo al
dbapi()
método de clase en el siguiente enlace:https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47
Puede ver que el
dbapi()
método, que utiliza un backend de base de datos para importar la biblioteca de base de datos específica del proveedor que necesita a pedido, es un método de clase porque necesita ejecutarse antes de que se inicien las instancias de una conexión de base de datos en particular, pero no puede puede ser una función simple o una función estática, porque quieren que pueda llamar a otros métodos de soporte que de manera similar podrían escribirse más específicamente en subclases que en su clase principal. Y si se envía a una función o clase estática, entonces se "olvida" y pierde el conocimiento sobre qué clase está realizando la inicialización.fuente
Hace poco quería una clase de registro muy liviana que produjera cantidades variables de salida dependiendo del nivel de registro que podría establecerse mediante programación. Pero no quería crear una instancia de la clase cada vez que quería generar un mensaje de depuración o error o advertencia. Pero también quería encapsular el funcionamiento de esta instalación de registro y hacerla reutilizable sin la declaración de ningún global.
Así que usé variables de clase y el
@classmethod
decorador para lograr esto.Con mi clase de registro simple, podría hacer lo siguiente:
Luego, en mi código, si quería escupir un montón de información de depuración, simplemente tenía que codificar
Los errores pueden ser eliminados con
En el entorno de "producción", puedo especificar
y ahora solo saldrá el mensaje de error. El mensaje de depuración no se imprimirá.
Aquí está mi clase:
Y un código que lo prueba solo un poco:
fuente
Los constructores alternativos son el ejemplo clásico.
fuente
Cuando un usuario inicia sesión en mi sitio web, se crea una instancia de un objeto Usuario () a partir del nombre de usuario y la contraseña.
Si necesito un objeto de usuario sin que el usuario esté allí para iniciar sesión (por ejemplo, un usuario administrador puede querer eliminar la cuenta de otro usuario, por lo que necesito crear una instancia de ese usuario y llamar a su método de eliminación):
Tengo métodos de clase para agarrar el objeto de usuario.
fuente
Creo que la respuesta más clara es la de AmanKow . Se reduce a cómo desea organizar su código. Puede escribir todo como funciones de nivel de módulo que están envueltas en el espacio de nombres del módulo, es decir
El código de procedimiento anterior no está bien organizado, como puede ver después de solo 3 módulos se vuelve confuso, ¿qué hace cada método? Puede usar nombres descriptivos largos para funciones (como en java) pero aún así su código se vuelve inmanejable muy rápido.
La forma orientada a objetos es dividir su código en bloques manejables, es decir, las clases, los objetos y las funciones pueden asociarse con instancias de objetos o con clases.
Con las funciones de clase, obtiene otro nivel de división en su código en comparación con las funciones de nivel de módulo. Por lo tanto, puede agrupar funciones relacionadas dentro de una clase para hacerlas más específicas a una tarea que asignó a esa clase. Por ejemplo, puede crear una clase de utilidad de archivo:
De esta manera es más flexible y más fácil de mantener, agrupa las funciones juntas y es más obvio para lo que hace cada función. También evita conflictos de nombres, por ejemplo, la copia de la función puede existir en otro módulo importado (por ejemplo, copia de red) que usa en su código, por lo que cuando usa el nombre completo FileUtil.copy () elimina el problema y ambas funciones de copia se puede usar uno al lado del otro.
fuente
FileUtil
métodos de clase como funciones de unfile_util
módulo, sería comparable y no abusaría de OOP cuando no existan objetos (en realidad, podría argumentar que es preferible, porque no termina confrom file_util import FileUtil
u otra verbosidad). Los conflictos de nombres se pueden evitar de manera similar en el código de procedimiento haciendo enimport file_util
lugar de hacerlofrom file_util import ...
.¿Honestamente? Nunca he encontrado un uso para el método estático o método de clase. Todavía tengo que ver una operación que no se puede hacer usando una función global o un método de instancia.
Sería diferente si Python usara miembros privados y protegidos más como lo hace Java. En Java, necesito un método estático para poder acceder a los miembros privados de una instancia para hacer cosas. En Python, eso rara vez es necesario.
Por lo general, veo personas que usan métodos estáticos y métodos de clase cuando todo lo que realmente necesitan hacer es usar mejor los espacios de nombres a nivel de módulo de Python.
fuente
Le permite escribir métodos de clase genéricos que puede usar con cualquier clase compatible.
Por ejemplo:
Si no lo usa
@classmethod
, puede hacerlo con la palabra clave self pero necesita una instancia de Class:fuente
Solía trabajar con PHP y recientemente me preguntaba, ¿qué pasa con este método de clase? El manual de Python es muy técnico y muy breve en palabras, por lo que no ayudará a comprender esa característica. Estaba buscando y buscando en Google y encontré la respuesta -> http://code.anjanesh.net/2007/12/python-classmethods.html .
Si eres flojo, haz clic en él. Mi explicación es más corta y más abajo. :)
en PHP (tal vez no todos conocen PHP, pero este lenguaje es tan sencillo que todos deberían entender de lo que estoy hablando) tenemos variables estáticas como esta:
La salida será en ambos casos 20.
Sin embargo, en Python podemos agregar el decorador @classmethod y, por lo tanto, es posible tener la salida 10 y 20 respectivamente. Ejemplo:
Inteligente, ¿no?
fuente
B.setInnerVar(20)
se10
omitió , se imprimiría dos veces (en lugar de dar un error en la segunda llamada echoInnerBar () que noinner_var
se definió.Los métodos de clase proporcionan un "azúcar semántico" (no sé si este término se usa ampliamente) o "conveniencia semántica".
Ejemplo: tienes un conjunto de clases que representan objetos. Es posible que desee tener el método de clase
all()
ofind()
escribirUser.all()
oUser.find(firstname='Guido')
. Eso podría hacerse usando funciones de nivel de módulo, por supuesto ...fuente
Lo que me llamó la atención , proveniente de Ruby, es que el llamado método de clase y el llamado método de instancia es solo una función con significado semántico aplicado a su primer parámetro, que se pasa silenciosamente cuando la función se llama como método de un objeto (es decir
obj.meth()
).Normalmente, ese objeto debe ser una instancia, pero el
@classmethod
decorador de métodos cambia las reglas para pasar una clase. Puede llamar a un método de clase en una instancia (es solo una función): el primer argumento será su clase.Debido a que es solo una función , solo se puede declarar una vez en cualquier ámbito (es decir,
class
definición). Si sigue, por lo tanto, como sorpresa para un Rubyist, que no puede tener un método de clase y un método de instancia con el mismo nombre .Considera esto:
Puedes llamar
foo
en una instanciaPero no en una clase:
Ahora agregue
@classmethod
:Llamar a una instancia ahora pasa su clase:
como lo hace llamar a una clase:
Es solo la convención la que dicta que usamos
self
para ese primer argumento en un método de instancia ycls
en un método de clase. No utilicé ninguno aquí para ilustrar que es solo un argumento. En Ruby,self
es una palabra clave.Contraste con Ruby:
El método de clase Python es solo una función decorada y puede usar las mismas técnicas para crear sus propios decoradores . Un método decorado envuelve el método real (en el caso de
@classmethod
que pase el argumento de clase adicional). El método subyacente sigue ahí, oculto pero aún accesible .nota al pie: escribí esto después de un choque de nombres entre una clase y un método de instancia despertó mi curiosidad. Estoy lejos de ser un experto en Python y me gustaría recibir comentarios si algo de esto está mal.
fuente
super()
). AFICT, la "magia" ocurre cuando se establece o se lee un atributo. La llamadaobj.meth(arg)
en Python (a diferencia de Ruby) significa simplemente(obj.meth)(arg)
. Nada se pasa silenciosamente a ningún lado,obj.meth
es solo un objeto invocable que acepta un argumento menos que la función desde la que se creó.obj.meth
, a su vez, significa simplementegetattr(obj, "meth")
.Este es un tema interesante. Mi opinión sobre esto es que el método de clase python funciona como un singleton en lugar de una fábrica (que devuelve una instancia producida de una clase). La razón por la que es un singleton es que hay un objeto común que se produce (el diccionario) pero solo una vez para la clase pero compartido por todas las instancias.
Para ilustrar esto aquí es un ejemplo. Tenga en cuenta que todas las instancias tienen una referencia al diccionario único. Este no es el patrón de fábrica, según tengo entendido. Esto es probablemente muy exclusivo de Python.
fuente
Me hacía la misma pregunta varias veces. Y a pesar de que los chicos aquí trataron de explicarlo, en mi humilde opinión, la mejor respuesta (y la más simple) que he encontrado es la descripción del método Class en la Documentación de Python.
También hay referencia al método estático. Y en caso de que alguien ya conozca los métodos de instancia (que supongo), esta respuesta podría ser la pieza final para poner todo junto ...
Se puede encontrar más y más detalles sobre este tema también en la documentación: La jerarquía de tipos estándar (desplácese hacia abajo hasta la sección Métodos de instancia )
fuente
@classmethod
puede ser útil para instanciar fácilmente objetos de esa clase de recursos externos. Considera lo siguiente:Luego en otro archivo:
Acceder a inst.x dará el mismo valor que la configuración ['x'].
fuente
Una clase define un conjunto de instancias, por supuesto. Y los métodos de una clase funcionan en las instancias individuales. Los métodos de clase (y las variables) son un lugar para colgar otra información relacionada con el conjunto de instancias sobre todo.
Por ejemplo, si su clase define un conjunto de estudiantes, es posible que desee variables o métodos de clase que definan cosas como el conjunto de calificaciones de las que los estudiantes pueden ser miembros.
También puede usar métodos de clase para definir herramientas para trabajar en todo el conjunto. Por ejemplo, Student.all_of_em () podría devolver todos los estudiantes conocidos. Obviamente, si su conjunto de instancias tiene más estructura que solo un conjunto, puede proporcionar métodos de clase para conocer esa estructura. Students.all_of_em (grade = 'juniors')
Técnicas como esta tienden a conducir a almacenar miembros del conjunto de instancias en estructuras de datos que están enraizadas en variables de clase. Debe tener cuidado para evitar frustrar la recolección de basura.
fuente