Могут ли модули иметь свойства? - PullRequest
6 голосов
/ 30 марта 2012

Можно ли добавить свойства и специальные методы в модули? Я хочу определить модуль так, чтобы его импорт действовал как экземпляр класса, а тело - как определение класса. По сути, это чтобы избежать уродливого синтаксиса, подобного этому:

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

например. игровой модуль будет выглядеть так:

_Speed = 1

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

И файл, использующий его:

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

Кроме того, возможно ли определить специальные методы (например, __call__)?

Для ясности, я не делаю различий между методами класса / экземпляра, поскольку я использую game.Game как синглтон / borg class.

Я тестировал, используя @property и определяя __bool__, но ни один из них не действует так, как я надеялся.

Редактировать (информация о том, почему я хочу использовать свойство):

У меня есть свойство game.speed, функция game.paused() и функция game.pause(bool). По сути, у меня есть временная переменная, используемая для хранения скорости игры, когда игра приостановлена. Существует частная переменная скорости, которая устанавливается в ноль, когда игра ставится на паузу. Я никогда не хочу, чтобы пользователь видел скорость равной нулю и мог изменять скорость во время приостановки игры, чтобы при возобновлении игры он использовал новую скорость.

Ответы [ 5 ]

12 голосов
/ 30 марта 2012

Python не заботится о том, что то, что в sys.modules, на самом деле является модулем.Таким образом, вы можете просто:

# game.py
class Game(object):
    pass

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

Теперь другие модули, которые import game получат экземпляр Game, а не оригинальный модуль.

Я не уверен, что рекомендую его, ноэто будет делать то, что вы хотите.

3 голосов
/ 30 марта 2012

Если вам нужен только синтаксис, как вы упомянули, вы можете определить класс и использовать атрибуты уровня класса

a1.py

class Game(object):
    paused = True


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

Ну, как вы и просилио свойствах в классе , то вы можете сделать что-то с помощью декоратора свойств и метода класса.Что-то вроде этого

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
2 голосов
/ 30 марта 2012

Кажется, вы хотите избежать доступа к элементам через модуль. Это довольно легко сделать.

Эти два эквивалента:

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

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

Хорошо, тогда как насчет этого:

# game.py

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

game = Game()

# from your module
from game import game
game.paused
0 голосов
/ 02 ноября 2018

хороший ответ здесь:

http://jtushman.github.io/blog/2014/05/02/module-properties/

Использование прокси-шаблона для реализации свойства модуля в целом. Элегантный.

class Proxy(object):
    def __init__(self, local):
        self.local = local
    def __getattr__(self, name):
        return getattr(self.local(), name)

# aliasing for better syntax        
module_property = Proxy

class User(object):
    """Contrived User Object"""
    def __init__(self, **kwargs):
        self.name = kwargs.get('name', 'billy')
    def speak(self):
        print("Well hello there!")
    def say_hi(self, to_whom):
        print("Hi there {}".format(to_whom))

@module_property
def current_user():
  return User()

Тогда его можно использовать как свойство:

from login_manager import current_user, User

if __name__ == '__main__':
    print current_user.name
    current_user.speak()
    current_user.say_hi('lauren')

В статье также упоминается устанавливаемый пакет (проект werkzerg), расширяющий эту концепцию.

0 голосов
/ 30 марта 2012

Я не думаю, что это сработает. Вам нужно будет импортировать модуль более одного раза, и Python будет выполнять его содержимое более одного раза. И это снова сбросит переменную скорости. Я думаю, что вам лучше использовать один класс Game, который хранит состояние игры. Это также сделает ваш код намного яснее и проще для понимания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...