开发者

@StaticMethod or @ClassMethod decoration on magic methods

开发者 https://www.devze.com 2023-01-08 19:27 出处:网络
I am trying to decorate the magic method __getitem__ to be a classmethod on the class. Here is a sample of what I tried. I don\'t mind using either classmethod or staticmethod decoration, but I am not

I am trying to decorate the magic method __getitem__ to be a classmethod on the class. Here is a sample of what I tried. I don't mind using either classmethod or staticmethod decoration, but I am not too sure how to do it. Here is what I tried:

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

However, when I try to call Settings['database'] I get the following error.

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

Can anyone tell me what I am doing wrong. Also, could someone suggest if there is better way to do this? I even tried using MetaClasses, but with little succ开发者_JS百科ess (as I don't know python too well).

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

 class Settings(object):
  __metaclass__ = Meta

Thanks in advance.


Python always looks up __getitem__ and other magic methods on the class, not on the instance. So, for example, defining a __getitem__ in a metaclass means that you can index the class (but you can't define it by delegating to a non-existent __getitem__ in type -- just as you can never define anything by delegating to other non-existent methods, of course;-).

So, if you need to index a class such as Settings, your custom metaclass must indeed define __getitem__, but it must define it with explicit code that performs the action you desire -- the return cls._config.get you want.

Edit: let me give a simplified example...:

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

Of course, if that was all there was to it, it would be silly to architect this code as "indexing a class" -- a class had better have instances with states and methods, too, otherwise you should just code a module instead;-). And why the "proper" access should be by indexing the whole class rather than a specific instance, etc, is far from clear. But I'll pay you the compliment of assuming you have a good design reason for wanting to structure things this way, and just show you how to implement such a structure;-).


Apart from Alex's (entirely correct) answer, it isn't clear what you actually want to do here. Right now you are trying to load the config when you instantiate the class. If you were to assign that _config to the class object, that would mean all instance of the class share the same config (and creating another instance would change all existing instances to point to the latest config.) Why are you trying to use the class to access this configuration, instead of a particular instance of the class? Even if you only ever have one configuration, it's much more convenient (and understandable!) to use an instance of the class. You can even store this instance in a module-global and call it 'Settings' if you like:

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

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

精彩评论

暂无评论...
验证码 换一张
取 消