2012-03-30 19 views
6

Czy można dodawać właściwości i metody specjalne do modułów? Chcę zdefiniować moduł taki, że importowanie działa jak instancja klasy, a ciało działa jako definicja klasy. Zasadniczo należy unikać brzydkiej składni:Czy moduły mogą mieć właściwości?

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

E.g. moduł gra będzie wyglądać następująco:

_Speed = 1 

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

i plik, używając go:

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

Ponadto, możliwe jest zdefiniowanie specjalnych metod (takich jak __call__)?

Dla jasności nie rozróżniam metod klasy/instancji, ponieważ używam klasy game.Game jako klasy singleton/borg.

Testowałem używając @property i definiując __bool__, ale żadne z nich nie działa tak, jak miałem nadzieję.

Edit (informacja o tym, dlaczego chcę użyć właściwość):

Mam właściwość game.speed, funkcję game.paused() i funkcję game.pause(bool). Zasadniczo mam tymczasową zmienną używaną do przechowywania prędkości gry, gdy gra jest wstrzymana. Istnieje prywatna zmienna prędkości, która jest ustawiona na zero, gdy gra jest wstrzymana. Nigdy nie chcę, aby użytkownik widział prędkość jako zero, i był w stanie zmienić prędkość, podczas gdy gra jest wstrzymana, tak aby po wznowieniu gry używał nowej prędkości.

+2

Dlaczego po prostu nie używać 'z gry import gry'? –

+0

Jak działają właściwości? Metaclass? W jaki sposób metaklasa odnosi się do klasy Game? – Darthfett

+2

Mówię, że jeśli używasz składni 'from ... import', nie potrzebujesz * właściwości w module. Osoby korzystające z tego modułu nie oczekują właściwości na nim, więc jeśli usuniesz właściwości z modułu i po prostu użyjesz 'form ... import' we własnym kodzie, uzyskasz tę samą czytelność, ale twój interfejs API będzie lepszy dostosuj się do oczekiwań innych programistów, co jest Dobrą Rzeczą. –

Odpowiedz

11

Pythonie nie obchodzi, że to, co w rzeczywistości jest sys.modules moduł. Więc można po prostu:

# game.py 
class Game(object): 
    pass 

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

Teraz inne moduły, które import game dostanie instancji Game, a nie oryginalny moduł.

Nie jestem pewien czy polecam, ale zrobi to, co chcesz.

+4

Whoa. To trochę czarnej magii. – bukzor

+0

Świetnie, dzięki! :) – Darthfett

+1

To ma pewien sens. Moduł przecież sam jest instancją klasy ('types.ModuleType'). Możesz napisać swoją klasę "Game" jako podklasę typu modułu, utworzyć instancję, a następnie będziesz miał coś, co jest w zasadzie modułem. Ale jak już powiedziałem, Python faktycznie nie sprawdza typu. – kindall

0

Nie sądzę, że to zadziała. Będziesz musiał zaimportować moduł więcej niż jeden raz, a Python wykona jego zawartość więcej niż jeden raz. I to zresetuje ponownie zmienną prędkości. Myślę, że lepiej jest użyć jednej klasy Game, która przechowuje stan gry. Dzięki temu Twój kod będzie dużo wyraźniejszy i łatwiejszy do naśladowania.

+0

Chcę, aby moduł został wykonany raz, problem, który mam, tworzy interfejs właściwości dla 'paused'. – Darthfett

+0

Dlatego twoje podejście nie zadziała. Będziesz potrzebował klasy z właściwościami do przechowywania lub obliczania stanu –

+0

Nie jestem przeciwnikiem posiadania klasy, jeśli nie muszę używać jej jako singleton/borg i tworzyć instancję za każdym razem, gdy chcę użyć wartość. – Darthfett

2

Wygląda na to, że chcesz uniknąć dostępu do elementów za pośrednictwem modułu. To dość łatwe do zrobienia.

Te dwa są równoważne:

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

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

Ok następnie, jak o tym:

# game.py 

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

game = Game() 

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

Ta składnia jest brzydka. Wymaga to napisania klasy, która używa wzorca singleton/borg, dla metod określania członków jako 'self. *' Lub 'Game. *' Oraz (dla wzorca borg) do użycia hackera inicjalizującego (aby uniknąć ponowne ustawienie członków każdego połączenia na "__init__"). – Darthfett

+0

W odpowiedzi na twoją drugą, było to coś, co próbowałem zrobić na początku, ale okazało się problematyczne, gdy gra wymagała jednego modułu, a ten moduł wymaga instancji klasy z gry. Daje błąd w następujący sposób: 'ImportError: nie można zaimportować nazwy gry ' – Darthfett

+0

@Darthfett circular dependency? Czy nie rozumiem cię? import gier X i X importuje grę? –

3

Jeśli wszystko czego szukasz jest składnia, jak wspomniano, to można zdefiniować klasę i poziom klasa użycie atrybutów

a1.py

class Game(object): 
    paused = True 


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

Cóż, kiedy pytałeś o Properties on Class, możesz zrobić coś z dekoratorem nieruchomości i metodą class. Czegos potrzebowalem jak ten

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

Problem polega na użyciu właściwości. Chcę, aby 'paused' było obliczane, ponieważ nigdy nie jest przechowywane. – Darthfett

+0

@Darthfett - Rozumiem. Zaktualizowałem moją odpowiedź. –

+1

Zgodnie z odpowiedzią, którą podałeś, nie działa ona dla seterów. Próbowałem dać [SSCCE] (http://sscce.org/), dlatego nie wspomniałem o tym, ale potrzebuję także seterów dla innych członków gry. – Darthfett

Powiązane problemy