2012-03-30 19 views
6

¿Es posible agregar propiedades y métodos especiales a los módulos? Quiero definir un módulo tal que importarlo actúa como una instancia de clase, y el cuerpo actúa como una definición de clase. Esencialmente, es para evitar una sintaxis fea como esta:¿Los módulos pueden tener propiedades?

import game 
if game.Game().paused: 
    print("The game is paused") 

E.g. el módulo de juego se vería así:

_Speed = 1 

@property 
def paused(): 
    return _Speed == 0 

y el archivo de usarlo:

import game 
if game.paused: 
    print("The game is paused") 

Además, es posible definir métodos especiales (como __call__)?

Para ser claros, no diferencio entre los métodos de clase/instancia, ya que estoy usando game.Game como clase singleton/borg.

he probado usando @property y definiendo __bool__, pero ni actúa como esperaba.

Editar (información sobre por qué quiero usar una propiedad):

que tiene una propiedad game.speed, una función y una función game.paused()game.pause(bool). Esencialmente, tengo una variable temporal utilizada para almacenar la velocidad del juego cuando el juego está en pausa. Hay una variable de velocidad privada que se establece en cero cuando el juego está en pausa. Nunca quiero que el usuario vea la velocidad como cero, y pueda modificar la velocidad mientras el juego está en pausa, de modo que cuando se reanude el juego, use la nueva velocidad.

+2

¿Por qué no usar 'from game import Game'? –

+0

¿Cómo funcionarían las propiedades? Una metaclase? ¿Cómo se referiría la metaclase a la clase Game? – Darthfett

+2

Estoy diciendo que si usa la sintaxis 'from ... import', * no necesita * propiedades en el módulo. Las personas que usan su módulo no esperan que haya propiedades en él, de modo que si suelta las propiedades del módulo y simplemente usa 'form ... import' en su propio código, obtendrá la misma legibilidad, pero su API mejorará cumplir con las expectativas de otros programadores, que es una buena cosa. –

Respuesta

11

Python no le importa que lo que está en sys.modules es en realidad un módulo. Lo que sólo puede:

# game.py 
class Game(object): 
    pass 

import sys 
sys.modules["game"] = Game() 

Ahora otros módulos que import game obtendrá el ejemplo Game, no el módulo original.

No estoy seguro de que lo recomiende, pero hará lo que quiera.

+4

Whoa. Eso es algo de magia negra. – bukzor

+0

Genial, gracias! :) – Darthfett

+1

Tiene un cierto tipo de sentido. Un módulo, después de todo, es en sí mismo una instancia de una clase ('types.ModuleType'). En realidad, podría escribir su clase 'Game' como una subclase del tipo de módulo, crear una instancia, y luego tendría algo que es básicamente un módulo. Pero como dije, Python en realidad no verifica el tipo. – kindall

0

No creo que esto vaya a funcionar. Tendrá que importar el módulo más de una vez y Python ejecutará su contenido más de una vez. Y eso restablecerá la variable de velocidad nuevamente. Creo que es mejor que utilices una única clase de Juego que almacene el estado del juego. También mantendrá su código mucho más claro y más fácil de seguir.

+0

Quiero que el módulo se ejecute una vez, el problema que tengo es crear una interfaz de propiedad para 'paused'. – Darthfett

+0

Es por eso que su enfoque no va a funcionar. Necesitarás una clase con propiedades para almacenar o calcular el estado –

+0

No estoy en contra de tener una clase, si no tengo que usarla como singleton/borg, y crear una instancia cada vez que quiero usar una clase valor. – Darthfett

2

Parece que desea evitar el acceso a los elementos a través del módulo. Eso es bastante fácil de hacer.

Estos dos son equivalentes:

import game 
if game.Game().paused: 
    print("The game is paused") 

from game import Game 
if Game().paused: 
    print("The game is paused") 

Ok entonces, ¿qué tal esto:

# game.py 

class Game(object): 
    @property 
    def paused(): 
     return True 

game = Game() 

# from your module 
from game import game 
game.paused 
+0

Esta sintaxis es fea. Me requiere escribir una clase para usar un patrón singleton/borg, para que los métodos se refieran a los miembros como 'self. *' O 'Game. *', Y (para borg pattern) para usar un hack de inicialización (para evitar restableciendo miembros cada llamada a '__init__'). – Darthfett

+0

En respuesta a su segundo, era algo que estaba tratando de hacer al principio, pero resultó ser problemático cuando el juego requería un módulo, y ese módulo requiere la instancia de clase del juego. Te da un error como el siguiente: 'ImportError: no se puede importar el nombre del juego' – Darthfett

+0

@Darthfett circular dependency? ¿O te estoy malinterpretando? juego importaciones X y X importa juego? –

3

Si todo lo que buscas es la sintaxis como usted ha mencionado, a continuación, se puede definir una clase y atributos de nivel de clase uso

a1.py

class Game(object): 
    paused = True 


>>> from a1 import Game 
>>> Game.paused 
True 
>>> Game.paused = False 
>>> Game.paused 
False 

Bueno, como le preguntó sobre el Properties on Class, entonces usted puede hacer algo con propiedad y decorador classmethod. Soemthing como esto

class ClassProperty(property): 
    def __get__(self, cls, owner): 
     return self.fget.__get__(None, owner)() 

class Game(object): 
    stage = True 
    @ClassProperty 
    @classmethod 
    def paused(cls): 
     return Game.stage == True 

>>> from a1 import Game 
>>> Game.paused 
True 
+0

El problema radica en usar una propiedad. Quiero que 'paused' se calcule, ya que nunca se almacena. – Darthfett

+0

@Darthfett - Entendido. Actualizado mi respuesta. –

+1

De acuerdo con la respuesta que vinculó, no funciona para los instaladores. Intenté dar un [SSCCE] (http://sscce.org/) y es por eso que no lo mencioné, pero también necesito setters para otros miembros del juego. – Darthfett

Cuestiones relacionadas