魔术方法上的 @StaticMethod 或 @ClassMethod 装饰

发布于 2024-09-10 11:44:29 字数 1030 浏览 4 评论 0原文

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

谁能告诉我我做错了什么。另外,有人可以建议是否有更好的方法来做到这一点?我什至尝试使用元类,但收效甚微(因为我不太了解 python)。

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

 class Settings(object):
  __metaclass__ = Meta

提前致谢。

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 success (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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

征棹 2024-09-17 11:44:29

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

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

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;-).

Oo萌小芽oO 2024-09-17 11:44:29

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

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

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

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')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文