Jak mogę utworzyć obiekt i dodać do niego atrybuty?

Chcę utworzyć dynamiczny obiekt (wewnątrz innego obiektu) w Pythonie, a następnie dodać do niego atrybuty.

Próbowałem:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')
Ale to nie zadziałało. Jakieś pomysły?

edit:

Ustawiam atrybuty z pętli for, która przecina listę wartości, np.

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

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

W powyższym przykładzie otrzymałbym obj.a.attr1, obj.a.attr2, obj.a.attr3.

Użyłem funkcji setattr ponieważ nie wiedziałem jak zrobić obj.a.NAME z for pętla.

Jak ustawić atrybut na podstawie wartości p w powyższym przykładzie?

Author: Martin Thoma, 2010-05-13

15 answers

Możesz użyć mojego starożytnego przepisu Bunch , ale jeśli nie chcesz tworzyć" klasy bunch", bardzo prosta już istnieje w Pythonie - wszystkie funkcje mogą mieć dowolne atrybuty (w tym funkcje lambda). Tak więc następujące dzieła:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')
Czy utrata jasności w porównaniu z przepisem czcigodnego jest OK, to decyzja stylowa, którą oczywiście pozostawiam tobie.
 161
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-13 14:49:46

Wbudowany object może być utworzony, ale nie może mieć żadnych atrybutów ustawionych na nim. (Chciałbym, żeby mogło, w tym właśnie celu.) Nie posiada __dict__ do przechowywania atrybutów.

Generalnie robię to:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

Kiedy Mogę, nadaję Object klasie bardziej wymowną nazwę, w zależności od tego, jakie dane w niej umieszczam.

Niektórzy ludzie robią inną rzecz, gdzie używają podklasy dict, która umożliwia dostęp do atrybutów, aby dostać się do kluczy. (d.key zamiast d['key'])

Edit: aby dodać do twojego pytania, użycie setattr jest w porządku. Po prostu nie można używać setattr na object() instancjach.

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)
 264
Author: FogleBird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-13 15:02:11

Jest types.SimpleNamespace klasa w Pythonie 3.3+:

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

collections.namedtuple, typing.NamedTuple może być używany dla obiektów niezmiennych. PEP 557 -- Klasy danych sugeruje zmienną alternatywę.

Aby uzyskać bogatszą funkcjonalność, możesz wypróbować attrs pakiet . Zobacz przykładowe użycie .

 83
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 18:02:23

Jest kilka sposobów na osiągnięcie tego celu. Zasadniczo potrzebujesz obiektu, który można rozszerzyć.

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()
 31
Author: evilpie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-05 14:16:21

Teraz możesz zrobić (Nie wiem czy to ta sama odpowiedź co evilpie):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
 16
Author: andreabedini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-13 00:32:55

Moduł mock jest w zasadzie do tego stworzony.

import mock
obj = mock.Mock()
obj.a = 5
 14
Author: Dunatotatos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-09 15:47:27

Wypróbuj poniższy kod:

$ 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']
 10
Author: neldor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-10 13:03:54

As docs say:

Uwaga: object czy nie mA __dict__, więc nie można przypisać dowolnych atrybutów do instancji klasy object.

Możesz po prostu użyć instancji dummy-class.

 7
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-13 14:43:29

Możesz również użyć obiektu klasy bezpośrednio; tworzy on Przestrzeń nazw:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')
 3
Author: Ernesto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 18:13:43

Te rozwiązania są bardzo pomocne podczas testów. Bazując na odpowiedziach innych robię to w Pythonie 2.7.9 (bez staticmethod dostaję TypeError (niezwiązana metoda...):

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4
 2
Author: Robpol86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-27 20:34:35

Jakich obiektów używasz? Po prostu próbowałem tego z przykładową klasą i działało dobrze:

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

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

I mam 123 jako odpowiedź.

Jedyną sytuacją, w której widzę to niepowodzenie, jest próba setattr na zbudowanym obiekcie.

Update: z komentarza wynika powtórzenie: dlaczego nie można dodać atrybutów do obiektu w Pythonie?

 0
Author: jneves,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")
 0
Author: lmokto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-27 19:41:59

Coming to this late in the day, ale oto mój pennyworth z obiektem, który po prostu zdarza się trzymać kilka przydatnych ścieżek w aplikacji, ale możesz dostosować go do wszystkiego, gdzie chcesz pewien dict informacji, do których możesz uzyskać dostęp za pomocą notacji getattr i kropki (co jest tym, co myślę, że to pytanie jest naprawdę o): {]}

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

To jest fajne bo teraz:

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

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

Więc to używa obiektu function, jak powyższe odpowiedzi, ale używa funkcji, aby uzyskać wartości (możesz nadal używać (getattr, x_path, 'repository') zamiast x_path('repository') jeśli wolisz).

 0
Author: Paul Whipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 02:17:04

W inny sposób widzę, w ten sposób:

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)
 -1
Author: Pablo Emmanuel De Leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 18:04:39

Wszystko jest w dokumentach .

TLDR: musisz potwierdzić return_value własność mocka, reszta to 'magia'.

Przykład:

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!')
 -1
Author: Oleg Belousov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-31 12:10:58