0

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

14

Описание проблемы:

Привет! У меня возник вопрос, когда я наткнулся на фрагмент кода, который ожидал объект с определённым набором атрибутов, но не указывал, какого типа должен быть этот объект.

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

Более коротким решением было бы создать обобщённый класс и затем устанавливать атрибуты для его экземпляров. Для тех, кто думал о использовании экземпляра класса 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)?

5 ответ(ов)

0

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

class Data: pass

Data.foo = 1
Data.bar = 2

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

0

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

Это работает отлично.

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

namedtuple предоставляет удобный способ создавать неизменяемые объекты с именованными полями, что улучшает читаемость вашего кода. В приведённом примере Data представляет собой контейнер для двух логических значений: do_good_stuff и do_bad_stuff. После создания экземпляра options вы можете обращаться к полям, как к атрибутам объекта, что делает код более понятным.

0

Самый короткий способ, который я знаю, выглядит так:

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

В этом примере атрибуты с дефисами не будут работать, поскольку дефис не является допустимым символом в именах атрибутов. Поэтому рекомендуется использовать dict для создания атрибутов с корректными именами.

0

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

Пример:

obj = type('', (), {})()
obj.hello = "hello"
obj.world = "world"
print(obj.hello, obj.world)  # выведет "hello world"

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

  • Первый аргумент '' — это имя нового типа. Мы не заботимся о названии, поэтому оставляем его пустым.
  • Второй аргумент () — это кортеж базовых типов. Здесь object подразумевается по умолчанию.
  • Третий аргумент — это словарь атрибутов нового объекта. Мы начинаем без атрибутов, поэтому он пустой {}.

В итоге мы создаём новый экземпляр этого нового типа с помощью ().

0

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь