2008-10-17 3 views
9

Я хотел бы создать тривиальный одноразовый объект 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' 

Что является самым простым «вещий» способ создать объект, который может использоваться таким образом, предпочтительно без необходимости создания дополнительного вспомогательного класса?

ответ

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

Это имеет функцию удаления какой-то беспорядок из вашего сценария. Значения по умолчанию легко найти и изменить, поскольку они оцеплены в собственном модуле. Если позже ваше приложение выросло, вы можете легко получить доступ к опциям из других модулей.

Это шаблон, который я часто использую, и сердечно рекомендую, если вы не возражаете против того, чтобы ваше приложение становилось больше одного модуля. Или, начните с пользовательского класса и позже добавьте его в модуль, если ваше приложение вырастет до нескольких модулей.

14

The collections module отрастил namedtuple функцию в 2.6:

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) 
+0

я не был осведомлен о `namedtuple` класса так что спасибо за ссылки. Но мне нужен изменяемый объект (полезный, например, при обработке командной строки). Кроме того, инициализация экземпляра `namedtuple` на самом деле не является полностью доступной для чтения при использовании для этой цели. – mhagger 2008-10-17 12:48:48

+0

Если вы посмотрите в документе namedtuple doc, вы увидите, что существует более ясная опция инициализации (по-прежнему неизменяемая, извините), например: «opt (VERBOSE = True, IGNORE_WARNINGS = False)» – gimel 2008-10-17 13:37:44

+0

Именованные кортежи безупречно круты. См. Эту статью http://www.artima.com/weblogs/viewpostP.jsp?thread=236637, а также этот рецепт, если вы не на Python 2.6 http://code.activestate.com/recipes/500261/ – 2011-06-24 08:03:55

5

Я использую attrdict:

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

В зависимости от вашей точки зрения, вы, вероятно, думаете, что это либо большой kludge или довольно умный. Но все, что вы думаете, он делает для приятного глаза коды, и совместят с 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 
+0

попробуйте это : ad ['foo-bar'] = 'oopsy' – 2008-10-17 14:11:38

+1

@Jeremy - не знаю, в чем проблема: >>> ad ['foo-bar'] = 'oopsy' >>> ad {'baz' : 'hello', 'foo': 100, 'bar': 200, 'foo-bar': 'oopsy'} – davidavr 2008-10-17 15:33:01

2

Упрощая davraamides's suggestion, можно использовать следующее:

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

которого

  1. Не так глупо.

  2. Не загрязняет пространство имен каждого объекта стандартными методами dict; например, ad.has_key не определен для объектов типа attrdict2.

Кстати, это еще проще инициализировать экземпляры attrdict или attrdict2:

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

Конечно, attrdict2 не совместим с dict.

Если вам не нужно магическое поведение инициализации, вы можете даже использовать

class attrdict3(object): 
    pass 

ad = attrdict3() 
ad.foo = 100 
ad.bar = 200 

Но я все еще надеялся на решение, которое не требует дополнительного класса.

1

можно использовать

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

options.VERBOSE = False 

if options.VERBOSE: 
    ... 

, используя сам объект класса (не экземпляр класса!), Как место для хранения отдельных параметров. Это краток и удовлетворяет всем требованиям, но это похоже на неправильное использование концепции класса. Это также привело бы к путанице, если бы пользователь создал экземпляр класса options.

(Если нужно было несколько экземпляров объектов опции-холдинг, это было бы очень хорошим решение. - класс значения поставок определения по умолчанию, которые могут быть переопределены в отдельных случаях)

1

Абсолютно простейший класс чтобы сделать работу является:

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

это может быть позже использовано в качестве:

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

namedtuple (как другие комментировало предложить ed) - это более продвинутый класс, который дает вам больше возможностей. Если вы все еще используете Python 2.5, то реализация 2.6's namedtuple основана на http://code.activestate.com/recipes/500261/

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) 
['__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'] 
3

Просто создайте модуль под названием «Параметры».ру и импортировать его. Поместите значения параметров по умолчанию в них как глобальные переменные.

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: 
    [...] 
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.

-2

простой объект и именованные кортежи путь

Смежные вопросы