2012-08-22 12 views
6

Tengo algunas clases que están muy extendidas en mi aplicación Python y que deberían tener solo una instancia global (por ejemplo, Logger, DbConnection). Python no admite variables/métodos estáticos en una clase, por lo que la forma habitual de Java/C++ para crear un singleton aquí no funciona. He buscado alternativas para implementar singleton en Python. Quiero una implementación simple (sin metaprogramación si es posible) y limpia. Esto se ve bien:Globales y singletons en Python

class MyClass(object): 
    def a(): 
     pass 

singleton = MyClass() 

Usando el singleton sería simple como

import myClass 
myClass.singleton.a() 

La asignación directa podría ser reemplazada por una función de creación de objeto de inicialización si no es tan simple.

También podría crear una getInstance() en el alcance del módulo y usarla siempre para obtener myObj.

Pregunta 1) ¿Esto funciona bien? El código del módulo (asignación myObj) solo se ejecuta la primera vez que se importa en algún otro módulo y myObj no se creará cada vez que importo este módulo en algún lugar.

Un método alternativo que he visto es utilizar un módulo global. Algo así como:

from myClass1 import MyClass1 
from myClass2 import MyClass2 

myObj1 = MyClass1() 
myObj2 = MyClass2() 

El uso de este:

import globals 
globals.myObj1.a() 

que tienden a preferir la primera alternativa.

Pregunta 2) Entre las 2 soluciones, ¿qué recomiendas?

Pregunta 3) Una tercera solución sería pasar los objetos generalizados como Logger a varias clases/funciones, pero esta no es una buena solución. ¿Hay una mejor solución que no se menciona aquí?

Soy consciente de las desventajas del uso de variables globales y singletons. Sin embargo, tener un estado global no es un gran problema en mi aplicación. Preferiré soluciones que tengan claridad de código y sean fáciles de usar.

+0

la premis de su pregunta es incorrecta. primero, python admite métodos estáticos y variables. segundo, ¿por qué no está utilizando las bibliotecas estándar existentes para el registro y acceso a la base de datos? –

+0

Python admite directamente variables/métodos estáticos (sin hack de anotación)? Su segunda pregunta se desvía del problema (implementación singleton), reemplaza las clases de acceso logging/db por cualquier clase que sea singleton y se usa ampliamente en una aplicación. –

Respuesta

6

Si desea tener una clase logger que solo tenga una instancia, simplemente haga que sea un módulo separado.

# In logging.py 
def log(msg): 
    print msg 

A continuación, desde cualquier script que desee iniciar sesión.

from logging import log 
log("A critical error occured.") 
+1

Tengo atributos en mi clase Logger (como el nombre del archivo de registro). Si transformo mis métodos de clase en funciones de módulo, los atributos de clase anteriores se convertirían en variables de módulo. ¿No es eso un problema? (Por ejemplo, si el usuario usa "desde el registro de importación *" (lo sé mal, pero de todos modos), mis variables saturarían el espacio variable de la aplicación. –

+0

@ user1550682: Un módulo es realmente solo un singleton en Python. Es un objeto, solo hay una instancia del mismo, y puede pasarlo como cualquier otro valor. Por lo tanto, no hay problema. –

+5

@ user1550682 - prefija sus variables privadas con un guion bajo único y no se importarán con 'import *' declaración. ej. '_filename =" bla.bla "' – Aesthete

-1

¿La respuesta correcta a cómo hacer singletons? No lo hagas Debería pasar explícitamente una referencia a todo lo que necesita usarlo. Puede reducir el esfuerzo con las funciones de fábrica, las clases de envoltura y similares.

Incluso si hay algo, como la pantalla o el registrador que es de naturaleza global, aún debe pasarlo explícitamente para permitir la prueba de la unidad. Tenga en cuenta que esto solo se aplica a cosas destinadas a ser parte del diseño final. Si su registrador es solo un truco rápido para la depuración, siéntase libre de hacerlo global.

+0

Como mencioné en mi publicación original, soy consciente de los inconvenientes de usar singletons. Su uso es controvertido desde que escuché por primera vez sobre ellos hasta hoy. Pasar una variable de registrador a todas las clases y funciones (si están fuera de una clase) en una aplicación me parece utópico, nunca he visto una aplicación real que lo haga. –

+0

Lo he hecho algunas veces, aunque admitiéndolo en scripts relativamente simples. Y planeo hacerlo en mi proyecto actual una vez que esté más completo. Pero tienes razón de que es un poco utópico. – Antimony

+1

Alan: Muchas aplicaciones usan una instancia de registrador global o la pasan en un módulo de configuración que se importa en otras partes de la aplicación. Además, muchas aplicaciones también dependen de un módulo de aplicación o configuración, que almacena variables globales, instancias de singleton o subprocesos que deben utilizarse en toda la aplicación. Django y Apio son ejemplos de aplicaciones que hacen esto. Al utilizar un patrón de diseño proxy y estatal, simplifica la necesidad de depender de los singleton, aunque en última instancia eso es lo que está ocurriendo, simplemente en una forma diferente. –

0

considerar la creación de los siguientes:

  1. Un estado clase clase
  2. Un proxy

La clase estado creará un hilo que se inicializa en un init. módulo py La clase de estado tendrá métodos que pasen las instancias de clase a la secuencia y guarden un punto débil en ella.

Más tarde, una clase de proxy se puede utilizar para acceder a las instancias de clase en la secuencia. Si los objetos de la clase no se crean, el proxy creará una instancia de la clase deseada y la guardará en la secuencia.

Al usar este patrón, puede restringir el número de instancias de cada clase a 1 y asegurarse de que siempre que se ejecute una parte de la aplicación, no sea necesario volver a crear ninguna instancia que necesite ser utilizada globalmente. .