2

我正在尝试将魔术方法装饰__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

提前致谢。

4

2 回答 2

6

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

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

编辑:让我举一个简化的例子......:

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

当然,如果仅此而已,那么将此代码构建为“为类编制索引”将是愚蠢的——一个类最好也具有带有状态和方法的实例,否则您应该只编写一个模块代码; -)。为什么“正确”访问应该是通过索引整个类而不是特定实例等,还远不清楚。但是我会向您表示恭维,假设您有一个很好的设计理由想要以这种方式构建事物,并且只是向您展示如何实现这种结构;-)。

于 2010-07-21T15:56:35.220 回答
1

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

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

Settings = _Settings('/path/to/config.ini')
于 2010-07-21T16:03:19.297 回答