【问题标题】:@StaticMethod or @ClassMethod decoration on magic methods魔术方法上的 @StaticMethod 或 @ClassMethod 装饰
【发布时间】:2010-07-21 15:51:33
【问题描述】:

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

提前致谢。

【问题讨论】:

  • 与您的问题无关,但您忘记在__init__ 方法中分配给self._envself._config。类级属性_env_config 也没用。

标签: python decorator static-methods magic-methods


【解决方案1】:

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

因此,如果您需要索引诸如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

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

【讨论】:

  • 我讨厌我和你在同一个时区,grr :)
  • 我尝试将 Meta 类更改为 class Meta(type): def getitem__(cls, key): print 'Meta getitem on ', cls, ' key: ', key return cls. _config.get(cls._env, key) 但是,我仍然在 .Settings'> 键上获得 Meta getitem:数据库 Traceback(最后一次调用):文件“”,第 1 行,在 文件“”中,第 4 行,在 getitem 中 AttributeError: 'NoneType' object has no attribute 'get' 知道吗?
  • @Bobby,无法在 cmets 中读取代码——看看我的示例代码,它工作得很好,并发现我的工作代码和你的非工作代码之间有什么区别(或者,如果他们只是看起来和你一模一样,编辑你的问题,不是评论,添加“据称与我的相同”的代码不起作用,我们会看看我们是否可以为你发现不同之处;- )。
  • @Thomas, ;-) -- 那么你最好说服 Tim O'Reilly 将 OSCON 搬到东海岸(因为我现在在波特兰的 OSCON,或者...也许我们可以试试明尼苏达州的波特兰?-)。
  • @Alex:不,我只需要在山景城时不要访问 stackoverflow :)
【解决方案2】:

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

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

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

【讨论】:

  • 这就是要走的路:如果你发现自己想让一个类表现得像一个实例,你最好一开始就使用一个实例。
  • 你可能是对的。我正在尝试使设置全局可访问。定义配置环境后,我想为该配置加载设置(数据库、服务器、超时)。
猜你喜欢
  • 2016-03-17
  • 2012-07-30
  • 2022-01-21
  • 2015-01-03
  • 1970-01-01
  • 2011-10-04
  • 2021-03-30
  • 2021-08-14
  • 2020-04-11
相关资源
最近更新 更多