python:@StaticMethod或@ClassMethod修饰魔术方法

我试图将魔术方法__getitem__修饰为类上的一个类方法。这是我试过的一个样品。我不介意使用classmethod或staticmethod修饰,但我不太确定如何做到这一点。以下是我的尝试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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']时,我得到以下错误。

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

谁能告诉我哪里做错了吗?还有,有没有人能建议一下有没有更好的方法?我甚至尝试使用元类,但几乎没有成功(因为我对python不是很了解)。

1
2
3
4
5
6
 class Meta(type):
  def __getitem__(*args):
   return type.__getitem__(*args)

 class Settings(object):
  __metaclass__ = Meta

提前谢谢。


Python总是在类上查找__getitem__和其他神奇的方法,而不是在实例上。因此,例如,在元类中定义一个__getitem__意味着您可以索引该类(但是您不能通过在type中委托一个不存在的__getitem__来定义它——当然,正如您永远不能通过委托给其他不存在的方法来定义任何东西一样;-)。

因此,如果您需要索引一个类,比如Settings,那么您的自定义元类确实必须定义__getitem__,但是它必须使用显式代码来定义它,以执行您想要的操作——您想要的return cls._config.get

编辑:让我举一个简单的例子……

1
2
3
4
5
6
7
8
9
10
>>> class MyMeta(type):
...   def __getitem__(cls, k):
...     return cls._config.get(k)
...
>>> class Settings:
...   __metaclass__ = MyMeta
...   _config = dict(foo=23, bar=45)
...
>>> print Settings['foo']
23

当然,如果这就是全部内容,那么将这段代码架构为"索引一个类"将是愚蠢的——一个类最好也有带状态和方法的实例,否则您应该只编写一个模块;-)。为什么"正确"的访问应该通过索引整个类而不是一个特定的实例等等,这一点还远不清楚。但是,我要向您表示敬意,假设您有一个很好的设计理由想要以这种方式构造事物,并向您展示如何实现这样的结构;-)。


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

1
2
3
4
5
6
class _Settings(object):
    def __init__(self, fname):
        self._config = ...
    ...

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