在魔术方法上使用@StaticMethod或@ClassMethod装饰器
我正在尝试把魔法方法 __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
提前谢谢大家。
2 个回答
在Python中,查找__getitem__
和其他特殊方法时,总是从类本身去查,而不是从实例去查。举个例子,如果你在一个元类中定义了__getitem__
,那么你可以对类进行索引(但是你不能通过委托给一个不存在的__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
当然,如果事情就这么简单,那把这段代码设计成“索引一个类”就显得有些傻了——一个类最好还是有实例,有状态和方法,否则你不如直接写一个模块;-)。至于为什么“正确”的访问方式是通过索引整个类而不是特定的实例等,这一点并不清楚。不过,我会假设你有一个很好的设计理由想要这样构建结构,然后就告诉你怎么实现这样的结构;-)。
除了Alex的回答(完全正确)之外,这里其实不太清楚你想要做什么。现在你是在创建这个类的时候加载配置。如果你把这个_config赋值给类对象,那就意味着这个类的所有实例都共享同一个配置(而且创建一个新的实例会让所有已有的实例都指向最新的配置)。你为什么要用类来访问这个配置,而不是用类的某个具体实例呢?即使你只有一个配置,使用类的实例会更方便(也更容易理解!)。你甚至可以把这个实例存储在模块的全局变量中,叫它'设置'也可以:
class _Settings(object):
def __init__(self, fname):
self._config = ...
...
Settings = _Settings('/path/to/config.ini')