魔术方法上的@StaticMethod或@ClassMethod装饰

时间:2010-07-21 15:51:34

标签: python decorator static-methods magic-methods

我正在尝试将魔术方法__getitem__装饰成课堂上的类方法。这是我尝试的样本。我不介意使用classmethod或staticmethod装饰,但我不太清楚如何做到这一点。这是我试过的:

import ConfigParser

class Settings(object):
   _env = None
   _config = None

   def __init__(self, env='dev'):
    _env = env
    # find the file
    filePath = "C:\\temp\\app.config"

    #load the file
    _config = ConfigParser.ConfigParser()
    _config.read(filePath)

   @classmethod
   def __getitem__(cls, key): 
    return cls._config.get(cls._env, key)

   @classmethod
   def loadEnv(cls, env): 
    cls._env = env

但是,当我尝试拨打Settings['database']时,我收到以下错误消息。

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected Array[Type], got str

谁能告诉我我做错了什么。此外,有人可以建议是否有更好的方法来做到这一点?我甚至尝试过使用MetaClasses,但收效甚微(因为我不太了解python)。

 class Meta(type):
  def __getitem__(*args):
   return type.__getitem__(*args)

 class Settings(object):
  __metaclass__ = Meta

提前致谢。

2 个答案:

答案 0 :(得分:5)

Python总是在类上查找__getitem__和其他魔术方法,而不是在实例上查找。因此,例如,在元类中定义__getitem__意味着您可以索引(但您无法通过委派给不存在的__getitem__来定义它。 type - 就像你永远不能通过委托其他不存在的方法来定义任何东西一样; - )。

因此,如果您需要索引诸如Settings之类的类,您的自定义元类必须确实定义__getitem__,但它必须使用显式代码来定义它,以执行您想要的操作 - { {1}}你想要的。

修改:让我举一个简单的例子......:

return cls._config.get

当然,如果就是这样的话,那么将这段代码设计为“索引类”是愚蠢的 - 一个类最好也有状态和方法的实例,否则你应该只编写一个而不是模块;-)。为什么“适当的”访问应该通过索引整个类而不是特定的实例等,这一点远非明确。但是我会恭维你假设你有一个很好的设计理由想要用这种方式构建东西,并且只是告诉你如何来实现这样的结构; - )。

答案 1 :(得分:1)

除了Alex的(完全正确的)答案之外,目前还不清楚你在这里想做什么。现在,您正在尝试在实例化类时加载配置。如果您要将_config分配给类对象,这意味着该类的所有实例共享相同的配置(并且创建另一个实例会将所有现有实例更改为指向最新配置​​。)为什么要尝试使用< em> class 来访问这个配置,而不是类的特定实例?即使您只有一个配置,使用该类的实例也更方便(也可理解!)。您甚至可以将此实例存储在全局模块中,如果您愿意,可将其命名为“设置”:

class _Settings(object):
    def __init__(self, fname):
        self._config = ...
    ...

Settings = _Settings('/path/to/config.ini')