Estoy aprendiendo Python y mi más reciente lección fue que Python no es Java, y por lo acabo de pasar un tiempo convirtiendo a todos mis métodos de la Clase en funciones.
Ahora me doy cuenta de que no tengo necesidad de utilizar los métodos de la Clase para lo que yo iba a hacer con static
métodos en Java, pero ahora no estoy seguro de que cuando yo haría uso de ellos. Todos los consejos que puedo encontrar sobre Python métodos de la Clase es a lo largo de las líneas de los novatos como yo, debe alejarse de ellos, y la documentación estándar es de lo más opaco cuando se habla de ellos.
¿Alguien tiene un buen ejemplo del uso de un método de Clase en Python o, al menos, alguien me puede decir cuando los métodos de la Clase pueden ser razonablemente utilizados?
Respuestas
¿Demasiados anuncios?Métodos de la clase son para cuando usted necesita para tener métodos que no son específicas para ninguna instancia en particular, pero aún así involucrar a la clase de alguna manera. Lo más interesante de ellos es que no puede ser reemplazado por subclases, algo que simplemente no es posible en Java los métodos estáticos o Python del módulo de funciones de nivel.
Si usted tiene una clase MyClass
, y un nivel de módulo de función que opera en Miclase (la fábrica, la dependencia de la inyección de código auxiliar, etc.), hacen que sea un classmethod
. A continuación, estará disponible en las subclases.
Métodos de fábrica (alternativa constructores) son, de hecho, un ejemplo clásico de los métodos de la clase.
Básicamente, los métodos de la clase son adecuados en cualquier momento te gustaría tener un método que, naturalmente, cabe en el espacio de nombres de la clase, pero no está asociado con una instancia concreta de la clase.
Como un ejemplo, en el excelente unipath módulo:
Directorio actual
-
Path.cwd()
- Retorno de la corriente real de directorio; p.ej.,
Path("/tmp/my_temp_dir")
. Este es un método de clase.
- Retorno de la corriente real de directorio; p.ej.,
-
.chdir()
- Hacer auto el directorio actual.
Como el directorio actual es el proceso de ancho, la cwd
método no tiene ninguna instancia en particular con la que deben ser asociados. Sin embargo, el cambio cwd
para el directorio de una determinada Path
de instancia debe ser, de hecho, un método de instancia.
Hmmm... como Path.cwd()
en efecto, devuelven un Path
de instancia, supongo que puede ser considerada como un método de fábrica...
Piénselo de esta manera: normal métodos son útiles para ocultar los detalles del envío: puede escribir myobj.foo()
sin preocuparse de si el foo()
método es implementado por la myobj
de clase del objeto o de una de sus clases para los padres. Métodos de la clase son exactamente análoga a la presente, sino con el objeto de clase de lugar: se permiten llamar a MyClass.foo()
sin tener que preocuparse de si foo()
está implementado especialmente por MyClass
debido a la necesidad de su propia versión especializada, o si se trata de dejar a sus padres de clase manejar la llamada.
Métodos de la clase son esenciales cuando está haciendo el set-up o cálculo que precede a la creación de una instancia real, ya que hasta la instancia existe obviamente, no puede utilizar la instancia como el envío de punto para sus llamadas de método. Un buen ejemplo puede verse en la SQLAlchemy código fuente, echa un vistazo a las dbapi()
método de clase en el siguiente enlace:
http://hg.sqlalchemy.org/sqlalchemy/file/230819db717a/lib/sqlalchemy/dialects/mssql/pymssql.py
Se puede ver que el dbapi()
método, que un servidor de base de datos utiliza para importar el proveedor de base de datos específica biblioteca necesidades de la demanda, es un método de clase debido a que se debe ejecutar antes de instancias de una determinada conexión de base de datos empezar a crear - pero eso no puede ser una simple función o función estática, porque ellos quieren que sea capaz de llamar a otros, el apoyo a métodos que podrían también deben ser escritos más específicamente en las subclases que en su clase padre. Y si te envío a una función o estático de la clase, luego se "olvida" y perder el conocimiento acerca de la clase que está haciendo la inicialización.
Recientemente he querido un muy ligeros de peso de registro de clase, que sería la salida de cantidades variables de salida en función del nivel de registro que se podría establecer mediante programación. Pero yo no quiero crear una instancia de la clase cada vez que quería a la salida de un mensaje de depuración o de error o de advertencia. Pero yo también quería encapsular el funcionamiento de esta utilidad de registro y hacer que sea reutilizable sin la declaración de cualquier globales.
Así que utiliza las variables de la clase y el @classmethod
decorador para lograr esto.
Con mi simple Registro de clase, yo podría hacer lo siguiente:
Logger._level = Logger.DEBUG
Entonces, en mi código, si quería escupir un montón de información de depuración, yo simplemente tenía que código
Logger.debug( "this is some annoying message I only want to see while debugging" )
Errores se podrían poner con
Logger.error( "Wow, something really awful happened." )
En la "producción" medio ambiente", puedo especificar
Logger._level = Logger.ERROR
y ahora, sólo el mensaje de error será la salida. El mensaje de depuración no será impreso.
Aquí está mi clase:
class Logger :
''' Handles logging of debugging and error messages. '''
DEBUG = 5
INFO = 4
WARN = 3
ERROR = 2
FATAL = 1
_level = DEBUG
def __init__( self ) :
Logger._level = Logger.DEBUG
@classmethod
def isLevel( cls, level ) :
return cls._level >= level
@classmethod
def debug( cls, message ) :
if cls.isLevel( Logger.DEBUG ) :
print "DEBUG: " + message
@classmethod
def info( cls, message ) :
if cls.isLevel( Logger.INFO ) :
print "INFO : " + message
@classmethod
def warn( cls, message ) :
if cls.isLevel( Logger.WARN ) :
print "WARN : " + message
@classmethod
def error( cls, message ) :
if cls.isLevel( Logger.ERROR ) :
print "ERROR: " + message
@classmethod
def fatal( cls, message ) :
if cls.isLevel( Logger.FATAL ) :
print "FATAL: " + message
Y una parte de código que comprueba que sólo un poco:
def logAll() :
Logger.debug( "This is a Debug message." )
Logger.info ( "This is a Info message." )
Logger.warn ( "This is a Warn message." )
Logger.error( "This is a Error message." )
Logger.fatal( "This is a Fatal message." )
if __name__ == '__main__' :
print "Should see all DEBUG and higher"
Logger._level = Logger.DEBUG
logAll()
print "Should see all ERROR and higher"
Logger._level = Logger.ERROR
logAll()