【问题标题】:Can modules have properties? [duplicate]模块可以有属性吗? [复制]
【发布时间】:2012-04-13 19:15:31
【问题描述】:

是否可以向模块添加属性和特殊方法?我想定义一个模块,以便导入它就像一个类实例,而主体充当一个类定义。本质上,它是为了避免像这样丑陋的语法:

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 类。

我已经使用@property 进行了测试并定义了__bool__,但都没有达到我的预期。

编辑(关于我为什么要使用属性的信息):

我有一个属性game.speed、一个函数game.paused() 和一个函数game.pause(bool)。本质上,我有一个临时变量,用于在游戏暂停时存储游戏速度。当游戏暂停时,有一个私有速度变量设置为零。我从不希望用户看到速度为零,并且能够在游戏暂停时修改速度,以便在游戏恢复时使用新的速度。

【问题讨论】:

  • 为什么不直接使用from game import Game
  • 属性如何工作?元类?元类如何引用 Game 类?
  • 我是说如果你使用from ... import 语法,你不需要 模块的属性。使用你的模块的人不会期望它上面有属性,所以如果你从模块中删除属性并在你自己的代码中简单地使用form ... import,你可以获得相同的可读性,但你的 API 会更好地符合其他程序员' 期望,这是一件好事。
  • 我用更多信息更新了我的帖子。我有计算出来的值,但应该作为属性(而不是函数)。
  • Related: stackoverflow.com/q/880530/936083 -- 如果我将方法直接添加到模块对象,这可能会起作用吗?

标签: python properties module


【解决方案1】:

我认为这行不通。您需要多次导入模块,Python 将多次执行其内容。这将再次重置速度变量。我认为您最好使用存储游戏状态的单个 Game 类。它还将使您的代码更清晰,更易于遵循。

【讨论】:

  • 我希望模块执行一次,我遇到的问题是为paused 创建一个属性接口。
  • 这就是你的方法行不通的原因。您需要一个具有属性的类来存储或计算状态
  • 我不反对有一个类,如果我不必将它用作单例/borg,并且每次我想使用一个值时都创建一个实例。
【解决方案2】:

您似乎想避免通过模块访问项目。这很容易做到。

这两个是等价的:

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

【讨论】:

  • 这种语法很难看。它要求我编写一个类以使用单例/borg 模式,方法将成员称为self.*Game.*,并且(对于 borg 模式)使用初始化程序 hack(以避免重新设置成员每次致电__init__)。
  • 回应你的第二个,这是我一开始试图做的事情,但是当我有游戏需要一个模块时结果是有问题的,然后那个模块需要来自游戏的类实例.它给你一个像这样的错误:ImportError: cannot import name game
  • @Darthfett 循环依赖?还是我误会你了?游戏导入 X 和 X 导入游戏?
  • 在 Python 中,我们“是同意的成年人”。 Game 不是您的界面的一部分; game 实例是,所以在 Pythonic 视图中,不需要实例化控制“模式”。
  • @Josh Smeaton 是的,我不记得那个名字了。在我实际使用游戏中的东西的时候,一切都应该已经完全定义好了,所以如果我想导入一个全局的只是一个问题。
【解决方案3】:

如果您正在寻找的只是您提到的语法,那么您可以定义一个类并使用类级属性

a1.py

class Game(object):
    paused = True


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

好吧,正如您所询问的Properties on Class,那么您可以使用属性装饰器和类方法来做一些事情。像这样的

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

【讨论】:

  • 问题在于使用属性。我希望计算 paused,因为它永远不会被存储。
  • @Darthfett - 明白了。更新了我的答案。
  • 根据您链接的答案,它不适用于二传手。我试图给SSCCE 这就是为什么我没有提到这一点,但我也需要其他游戏成员的设置器。
  • 有没有什么原因不能用实例属性定义类,不能在模块中定义一个实例作为全局变量,from... import那个
  • 是的,setter 可能无法以这种方式进行。使用 Class 变量设置状态怎么样?当然,它不是对称的,我会说你的实例化方法会更干净。
【解决方案4】:

Python 并不关心sys.modules 中的内容实际上是一个模块。所以你可以:

# game.py
class Game(object):
    pass

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

现在import game 的其他模块将获得Game 实例,而不是原始模块。

我不确定我是否推荐它,但它会做你想要的。

【讨论】:

  • 哇。这是一些黑魔法。
  • 它有某种意义。毕竟,模块本身就是一个类的实例 (types.ModuleType)。您实际上可以将Game 类编写为模块类型的子类,实例化它,然后您将拥有基本上是模块的东西。但正如我所说,Python 实际上并不检查类型。
【解决方案5】:

这里的答案很好:

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 项目)。

【讨论】:

    猜你喜欢
    • 2010-10-27
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    相关资源
    最近更新 更多