@StaticMethod или @ClassMethod украшение магическими методами - PullRequest
1 голос
/ 21 июля 2010

Я пытаюсь украсить магический метод __getitem__, чтобы он стал классным методом в классе.Вот пример того, что я пробовал.Я не возражаю против использования классового или статического метода украшения, но я не слишком уверен, как это сделать.Вот что я попробовал:

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 ]

5 голосов
/ 21 июля 2010

Python всегда ищет __getitem__ и другие магические методы в классе, а не в экземпляре. Так, например, определение __getitem__ в метаклассе означает, что вы можете индексировать класс (но вы не можете определить его, делегировав несуществующему __getitem__ в 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

Конечно, если бы это было все, что было нужно, было бы глупо проектировать этот код как "индексирование класса" - классу лучше иметь экземпляры с состояниями и методами, иначе вы должны просто написать код модуль вместо ;-). И почему «правильный» доступ должен осуществляться путем индексации всего класса, а не конкретного экземпляра и т. Д., Далеко не ясно. Но я сделаю вам комплимент, если предположим, что у вас есть веская причина для конструирования таких вещей, и просто покажу вам , как реализовать такую ​​структуру; -).

1 голос
/ 21 июля 2010

Помимо ответа Алекса (полностью правильного), неясно, что вы на самом деле хотите здесь делать.Прямо сейчас вы пытаетесь загрузить конфигурацию при создании экземпляра класса.Если вы назначите этот _config объекту класса, это будет означать, что все экземпляры класса совместно используют одну и ту же конфигурацию (а создание другого экземпляра изменит все существующие экземпляры, чтобы они указывали на последнюю конфигурацию.)1001 * класс для доступа к этой конфигурации, а не к конкретному экземпляру класса?Даже если у вас есть только одна конфигурация, гораздо удобнее (и понятно!) Использовать экземпляр класса.Вы даже можете сохранить этот экземпляр в глобальном модуле и назвать его «Настройки», если хотите:

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

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