Самый короткий способ создания объекта с произвольными атрибутами в 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)?
Ответы
Ответ 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])
.)
Ответ 10
Вам может быть интересен "Struct", который является частью пакета IPython. Он делает то, что вы хотите сделать, с множеством полезных методов.
http://ipython.org/ipython-doc/rel-0.13/api/generated/IPython.utils.ipstruct.html
Ответ 11
Обычно это то, что вы использовали бы для dict, а не для создания класса вообще.