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

Python: создать объект и добавить к нему атрибуты

Я хочу создать динамический объект (внутри другого объекта) в Python и затем добавить к нему атрибуты.

Я пробовал:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

но это не сработало.

Любые идеи?

изменить:

Я устанавливаю атрибуты из цикла for, который перебирает список значений, например.

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

В приведенном выше примере я получил бы obj.a.attr1, obj.a.attr2, obj.a.attr3.

Я использовал функцию setattr, потому что я не знал, как сделать obj.a.NAME из цикла for.

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

4b9b3361

Ответ 1

Вы можете использовать мой древний рецепт Bunch, но если вы не хотите создавать "класс сгруппировки", очень просто один уже существует в Python - все функции могут иметь произвольные атрибуты (в том числе лямбда-функции). Итак, следующие работы:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

Является ли потеря ясности по сравнению с почтенным рецептом Bunch в порядке, это решение стиля, которое я, конечно, оставлю вам.

Ответ 2

Встроенный object может быть создан, но не может иметь никаких атрибутов, установленных на нем. (Я бы хотел, чтобы это было возможно для этой цели.) Для хранения атрибутов не существует __dict__.

Обычно я просто делаю это:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

Когда я могу, я даю классу object более значимое имя, в зависимости от того, какие данные я им вставляю.

Некоторые люди делают другое дело, где используют подкласс класса dict, который позволяет получить доступ к атрибутам ключей. (d.key вместо d['key'])

Изменить. Для добавления к вашему вопросу использование setattr в порядке. Вы просто не можете использовать setattr в object() экземплярах.

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)

Ответ 3

В Python 3.3+ types.SimpleNamespace:

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtuple, typing.NamedTuple может быть используется для неизменяемых объектов. PEP 557 - классы данных предлагает альтернативную альтернативу.

Для более богатой функциональности вы можете попробовать attrs пакет. См. пример использования.

Ответ 4

Есть несколько способов достижения этой цели. В принципе вам нужен объект, который можно продлить.

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

Ответ 5

Теперь вы можете сделать (не уверенный, если это тот же ответ, что и зло):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

Ответ 6

Попробуйте выполнить код ниже:

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']

Ответ 7

как docs говорят:

Примечание: object не имеет __dict__, поэтому вы не можете назначить произвольные атрибуты экземпляру класса object.

Вы можете просто использовать экземпляр фиктивного класса.

Ответ 8

В основном для этого используется модуль mock.

import mock
obj = mock.Mock()
obj.a = 5

Ответ 9

Эти решения очень полезны во время тестирования. Основываясь на всех остальных ответах, я делаю это в Python 2.7.9 (без staticmethod я получаю TypeError (unbound method...):

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

Ответ 10

Какие объекты вы используете? Просто попробовал это с классом образцов, и он работал нормально:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

И я получил 123 как ответ.

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

Обновление: из комментария это повторение: Почему вы не можете добавлять атрибуты к объекту в python?

Ответ 11

di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

Ответ 12

Подойдя к этому в конце дня, но вот мой pennyworth с объектом, который просто имеет некоторые полезные пути в приложении, но вы можете адаптировать его для чего угодно, где вы хотите получить информацию о том, что вы можете получить с помощью getattr и точечной нотации (вот что я думаю, что этот вопрос действительно есть):

import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

Это круто, потому что теперь:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

Таким образом, это использует объект функции, такой как приведенные выше ответы, но использует функцию для получения значений (вы можете использовать (getattr, x_path, 'repository'), а не x_path('repository'), если хотите).

Ответ 13

Другим способом я вижу, таким образом:

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

Ответ 14

Все это в docs.

TL;DR: вам нужно утверждать свойство return_value макета, остальное - "Магия".

Пример:

SomeConstructor = MagicMock()

SomeConstructor.return_value. \
    some_class_method.assert_called_once_with('cool!')

  SomeConstructor.return_value. \
        some_inner_property. \
        some_inner_method.assert_called_once_with('super cool!')