Кратчайший способ создания объекта с произвольными атрибутами в Python? - PullRequest
25 голосов
/ 17 февраля 2010

Эй, я только начал задумываться об этом, когда наткнулся на код, который ожидал объект с определенным набором атрибутов (но без указания типа этого объекта).

Одним из решений было бы создание нового класса с атрибутами, ожидаемыми в коде, но, поскольку я вызываю другой код, которому также нужны объекты с (другими) атрибутами, мне пришлось бы создавать все больше и больше классов.

Более коротким решением является создание универсального класса, а затем установка атрибутов для его экземпляров (для тех, кто думал об использовании экземпляра object вместо создания нового класса, который не будет работать с * 1006). * экземпляры не допускают новые атрибуты).

Последнее, самое короткое решение, которое я придумал, - это создание класса с конструктором, который принимает аргументы ключевых слов, как конструктор dict, а затем устанавливает их как атрибуты:

class data:
    def __init__(self, **kw):
        for name in kw:
            setattr(self, name, kw[name])

options = data(do_good_stuff=True, do_bad_stuff=False)

Но я не могу не чувствовать, что упустил что-то очевидное ... Разве нет встроенного способа сделать это (предпочтительно поддерживается в Python 2.5)?

Ответы [ 11 ]

22 голосов
/ 27 июня 2014

type('', (), {})() создаст объект, который может иметь произвольные атрибуты.

Пример:

obj = type('', (), {})()
obj.hello = "hello"
obj.world = "world"
print obj.hello, obj.world #will print "hello world"

type() с тремя аргументами создает новый тип.

Первый аргумент '' - это имя нового типа. Нас не волнует имя, поэтому мы оставляем его пустым.

Второй аргумент () - это кортеж базовых типов, здесь object (неявный).

Третий аргумент - это словарь атрибутов нового объекта - опять же нам все равно, это пустой словарь {}

И в конце мы создаем новый экземпляр этого нового типа с () в конце.

22 голосов
/ 17 февраля 2010

Исходный код можно немного упростить, используя __dict__:

In [1]: class data:
   ...:     def __init__(self, **kwargs):
   ...:         self.__dict__.update(kwargs)
   ...: 

In [2]: d = data(foo=1, bar=2)

In [3]: d.foo
Out[3]: 1

In [4]: d.bar
Out[4]: 2
16 голосов
/ 17 февраля 2010

Использование collections.namedtuple.

Хорошо работает.

from collections import namedtuple
Data = namedtuple( 'Data', [ 'do_good_stuff', 'do_bad_stuff' ] )
options = Data( True, False )
13 голосов
/ 17 февраля 2010

Это работает в 2.5, 2.6 и 3.1:

class Struct(object):
    pass

something = Struct()
something.awesome = abs

result = something.awesome(-42)

EDIT: Я подумал, что предоставление источника также поможет. http://docs.python.org/tutorial/classes.html#odds-and-ends

EDIT: В результат добавлено присваивание, так как я использовал для проверки интерактивные переводчики, а вы не можете.

11 голосов
/ 17 февраля 2010

Это самый короткий путь, который я знаю

>>> obj = type("myobj",(object,),dict(foo=1,bar=2))
>>> obj.foo
1
>>> obj.bar
2
>>> 

использование dict вместо {} гарантирует правильность имен ваших атрибутов

>>> obj = type("myobj",(object,),{"foo-attr":1,"bar-attr":2})
>>> obj.foo-attr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'myobj' has no attribute 'foo'
>>>
6 голосов
/ 20 декабря 2015

Функция - это объект. Таким образом, вы можете назначить атрибуты для функции. Или сделать один. Я думаю, это самый простой способ с точки зрения строк кода.

def hello():
    pass


hello.chook = 123

но самый простой и элегантный способ (но python> 3.3) - использовать simpleNamespace от Standard Libary https://docs.python.org/3/library/types.html#types.SimpleNamespace

>>> from types import SimpleNamespace
>>> foo = SimpleNamespace()
>>> foo.hello = "world"
6 голосов
/ 02 октября 2012

Используйте комбинацию между лямбда и встроенным типом, я думаю, это самый маленький способ сделать это:

obj = lambda **kwargs: type('obj', (object,), kwargs)()

options = obj(do_good_stuff=True, do_bad_stuff=False)

print options.do_good_stuff
print options.do_bad_stuff
4 голосов
/ 26 сентября 2013

Если вам не нужно передавать значения в конструкторе, вы можете сделать это:

class data: pass

data.foo = 1
data.bar = 2

Вы используете статические переменные-члены класса для хранения ваших данных.

0 голосов
/ 17 февраля 2010

Обычно это то, для чего вы будете использовать дикт, а не создавать класс вообще.

0 голосов
/ 17 февраля 2010

Вас может заинтересовать "Struct", который является частью пакета IPython.Он делает то, что вы хотите сделать, с множеством полезных методов.

http://ipython.org/ipython-doc/rel-0.13/api/generated/IPython.utils.ipstruct.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...