创建一个简单的一次性Python对象的便捷方法是什么?
我想创建一个简单的 Python 对象,用来存放一些命令行选项。我想做的事情大概是这样的:
options = ??????
options.VERBOSE = True
options.IGNORE_WARNINGS = False
# Then, elsewhere in the code...
if options.VERBOSE:
...
当然,我可以使用字典来实现,但用 options.VERBOSE
这种方式比 options['VERBOSE']
更容易读懂,也更容易输入。
我 以为 我应该能这样做:
options = object()
因为 object
是所有类对象的基础类型,所以应该可以看作是一个没有属性的类。但这样做不行,因为用 object()
创建的对象没有 __dict__
这个成员,因此无法给它添加属性:
options.VERBOSE = True
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'VERBOSE'
那么,最简单的“Python 风格”的方法是什么呢?希望能做到这一点,而不需要额外创建一个辅助类。
11 个回答
8
如果你坚持不想定义一个类,你可以利用一些现有的类。大多数对象属于“新式”类,这些类没有字典,但函数可以拥有任意的属性:
>>> x = lambda: 0 # any function will do
>>> x.foo = 'bar'
>>> x.bar = 0
>>> x.xyzzy = x
>>> x.foo
'bar'
>>> x.bar
0
>>> x.xyzzy
<function <lambda> at 0x6cf30>
一个问题是,函数本身已经有一些属性,所以用 dir(x) 查看时会有点乱:
>>> dir(x)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__',
'__module__', '__name__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__str__', 'foo',
'func_closure', 'func_code', 'func_defaults', 'func_dict',
'func_doc', 'func_globals', 'func_name', 'xyzzy']
15
collections模块在2.6版本中新增了一个叫做namedtuple的功能:
import collections
opt=collections.namedtuple('options','VERBOSE IGNORE_WARNINGS')
myoptions=opt(True, False)
>>> myoptions
options(VERBOSE=True, IGNORE_WARNINGS=False)
>>> myoptions.VERBOSE
True
namedtuple是不可变的,这意味着你只能在创建的时候给它的字段赋值。
在早期的Python版本中,你可以创建一个空的类:
class options(object):
pass
myoptions=options()
myoptions.VERBOSE=True
myoptions.IGNORE_WARNINGS=False
>>> myoptions.IGNORE_WARNINGS,myoptions.VERBOSE
(False, True)
9
根据你的需求,我觉得自定义类是最好的选择:
class options(object):
VERBOSE = True
IGNORE_WARNINGS = True
if options.VERBOSE:
# ...
为了更全面,另一种方法是使用一个单独的模块,比如 options.py
来封装你的选项默认值。
options.py
:
VERBOSE = True
IGNORE_WARNINGS = True
然后,在 main.py
中:
import options
if options.VERBOSE:
# ...
这样做的好处是可以减少你脚本中的杂乱。默认值很容易找到和修改,因为它们被放在了自己的模块里。如果以后你的应用程序变得更大,你可以很方便地从其他模块访问这些选项。
这是我经常使用的一种模式,如果你不介意你的应用程序比一个模块大,我会非常推荐这种方法。或者,你也可以先从自定义类开始,如果你的应用程序发展到多个模块,再扩展到一个模块。