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

时间:2008-10-17 10:47:50

标签: python

我想创建一个简单的一次性Python对象来保存一些命令行选项。我想做这样的事情:

options = ??????
options.VERBOSE = True
options.IGNORE_WARNINGS = False

# Then, elsewhere in the code...
if options.VERBOSE:
    ...

当然我可以使用字典,但options.VERBOSEoptions['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'

创建可以这种方式使用的对象的最简单的“pythonic”方法是什么,最好不必创建额外的帮助类?

11 个答案:

答案 0 :(得分:14)

collections module在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)

答案 1 :(得分:8)

根据您的要求,我会说自定义课程是您最好的选择:

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:
    # ...

这具有从脚本中删除一些混乱的功能。默认值易于查找和更改,因为它们在自己的模块中被封锁。如果以后您的应用程序增长,您可以轻松地从其他模块访问这些选项。

这是我经常使用的模式,如果你不介意你的应用程序比单个模块更大,那么我们会非常谨慎地推荐这种模式。或者,从自定义类开始,如果您的应用程序增长到多个模块,则稍后扩展到模块。

答案 2 :(得分:7)

为什么不使用optparse

from optparse import OptionParser
[...]
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
              help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
              action="store_false", dest="verbose", default=True,
              help="don't print status messages to stdout")

(options, args) = parser.parse_args()

file = options.filename
if options.quiet == True:
    [...]

答案 3 :(得分:6)

如果您坚持不必定义课程,则可以滥用某些现有课程。大多数对象属于没有dict的“新式”类,但函数可以具有任意属性:

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

答案 4 :(得分:5)

我使用attrdict

class attrdict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self.__dict__ = self

根据您的观点,您可能认为它既是一个大块头,也可能是一个非常聪明的人。但是无论你怎么想,它确实会产生漂亮的代码,并且与dict兼容:

>>> ad = attrdict({'foo': 100, 'bar': 200})
>>> ad.foo
100
>>> ad.bar
200
>>> ad.baz = 'hello'
>>> ad.baz
'hello'
>>> ad
{'baz': 'hello', 'foo': 100, 'bar': 200}
>>> isinstance(ad, dict)
True

答案 5 :(得分:4)

最佳做法是,David Eyk's answer中的其中一个选项让您感觉更好。

但是,要回答您的问题,您可以使用type功能创建一次性课程:

options = type('Options', (object,), { 'VERBOSE': True })()
options.IGNORE_WARNINGS = False

请注意,您可以提供初始字典,或者只是将其留空。

Options = type('Options', (object,), {})
options = Options()
options.VERBOSE = True
options.IGNORE_WARNINGS = False

不是非常pythonic。

答案 6 :(得分:3)

只需创建一个名为Options.py的模块,然后导入它。将默认选项值作为全局变量放在那里。

答案 7 :(得分:2)

简化davraamides's suggestion,可以使用以下内容:

class attrdict2(object):
    def __init__(self, *args, **kwargs):
        self.__dict__.update(*args, **kwargs)

其中

  1. 不是那么愚蠢。

  2. 不会使用dict的标准方法污染每个对象的命名空间;例如,ad.has_key没有为attrdict2类型的对象定义。

  3. 顺便说一句,初始化attrdictattrdict2的实例更为容易:

    >>> ad = attrdict2(foo = 100, bar = 200)
    

    当然,attrdict2dict不兼容。

    如果您不需要魔术初始化行为,您甚至可以使用

    class attrdict3(object):
        pass
    
    ad = attrdict3()
    ad.foo = 100
    ad.bar = 200
    

    但我仍然希望找到一个不需要辅助课程的解决方案。

答案 8 :(得分:1)

可以使用

class options(object):
    VERBOSE = True
    IGNORE_WARNINGS = False

options.VERBOSE = False

if options.VERBOSE:
    ...

,使用类对象本身(不是类的实例!)作为存储单个选项的位置。这简洁并且满足所有要求,但它似乎是对类概念的误用。如果用户实例化options类,它也会导致混淆。

(如果需要多个选项保持对象的实例,这将是一个非常好的解决方案 - 类定义提供默认值,可以在单个实例中覆盖它。)

答案 9 :(得分:1)

完成这项工作绝对最简单的课程是:

class Struct:
    def __init__(self, **entries): 
        self.__dict__.update(entries)

以后可以用作:

john = Struct(name='john doe', salary=34000)
print john.salary

namedtuple(正如另一个评论建议)是一个更高级的类,它为您提供更多功能。如果您仍在使用Python 2.5,可以在http://code.activestate.com/recipes/500261/

找到基于namedtuple的实现2.6 {

答案 10 :(得分:-2)

简单对象和命名元组是要走的路