Подтвердить что ты не робот

Самый короткий способ создания объекта с произвольными атрибутами в Python?

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

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

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

Последнее, самое короткое решение, с которым я столкнулся, состояло в том, чтобы создать класс с конструктором, который принимает аргументы ключевого слова, как конструктор 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)?

4b9b3361

Ответ 1

Исходный код можно немного упростить, используя __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

Ответ 2

Используйте collections.namedtuple.

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

from collections import namedtuple
Data = namedtuple( 'Data', [ 'do_good_stuff', 'do_bad_stuff' ] )
options = Data( True, False )

Ответ 3

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

Пример:

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

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

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

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

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

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

Ответ 4

Это работает в 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: Добавлено назначение результата, поскольку я использовал интерактивные интерпретаторы для проверки, и вы не можете быть.

Ответ 5

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

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

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

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

Ответ 7

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

def hello():
    pass


hello.chook = 123

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

>>> from types import SimpleNamespace
>>> foo = SimpleNamespace()
>>> foo.hello = "world"

Ответ 8

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

class data: pass

data.foo = 1
data.bar = 2

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

Ответ 9

Если я правильно понимаю ваш вопрос, вам нужны записи. Классы Python могут использоваться таким образом, что вы и делаете.

Я считаю, что самый пифонический способ иметь дело с "записями" - это просто... словари! Класс - это своего рода словарь по стероидам.

Пример вашего класса data - это, по сути, способ преобразования словаря в класс.

(На боковой ноте я предпочел бы использовать self.__setattr__(name, kw[name]).)

Ответ 11

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