创建一个简单的一次性Python对象的便捷方法是什么?

9 投票
11 回答
4017 浏览
提问于 2025-04-11 17:47

我想创建一个简单的 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:
    # ...

这样做的好处是可以减少你脚本中的杂乱。默认值很容易找到和修改,因为它们被放在了自己的模块里。如果以后你的应用程序变得更大,你可以很方便地从其他模块访问这些选项。

这是我经常使用的一种模式,如果你不介意你的应用程序比一个模块大,我会非常推荐这种方法。或者,你也可以先从自定义类开始,如果你的应用程序发展到多个模块,再扩展到一个模块。

撰写回答