Je veux créer un objet dynamique (à l'intérieur d'un autre objet) en Python, puis y ajouter des attributs.
J'ai essayé:
obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')
mais cela n'a pas fonctionné.
Des idées?
modifier:
Je configure les attributs à partir d'une boucle for
qui parcourt une liste de valeurs, par exemple.
params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()
for p in params:
obj.a.p # where p comes from for loop variable
Dans l'exemple ci-dessus, j'obtiendrais obj.a.attr1
, obj.a.attr2
, obj.a.attr3
.
J'ai utilisé la fonction setattr
parce que je ne savais pas comment faire obj.a.NAME
à partir d'une boucle for
.
Comment définir l'attribut en fonction de la valeur de p
dans l'exemple ci-dessus?
Vous pouvez utiliser mon ancien Bunch recette, mais si vous ne voulez pas créer de "classe de groupe", une très simple existe déjà en Python - toutes les fonctions peuvent avoir des attributs arbitraires (y compris les fonctions lambda). Donc, les travaux suivants:
obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')
Que la perte de clarté par rapport à la vénérable recette Bunch
soit correct, est une décision de style que je laisserai bien sûr à vous de décider.
La variable object
intégrée peut être instanciée mais aucun attribut ne peut y être défini. (J'aimerais bien pouvoir le faire, dans ce but précis.) Il n'a pas de __dict__
pour contenir les attributs.
Je fais généralement juste ceci:
class Object(object):
pass
a = Object()
a.somefield = somevalue
Lorsque je peux, je donne à la classe Object
un nom plus significatif, en fonction du type de données que je mets.
Certaines personnes font la même chose en utilisant une sous-classe de dict
qui permet aux attributs d'accéder aux clés. (d.key
au lieu de d['key']
)
Modifier : Pour l’ajout à votre question, utiliser setattr
convient. Vous ne pouvez simplement pas utiliser setattr
sur les instances object()
.
params = ['attr1', 'attr2', 'attr3']
for p in params:
setattr(obj.a, p, value)
Il y a types.SimpleNamespace
class dans Python 3.3+ :
obj = someobject
obj.a = SimpleNamespace()
for p in params:
setattr(obj.a, p, value)
# obj.a.attr1
collections.namedtuple
, typing.NamedTuple
pourrait être utilisé pour des objets immuables. PEP 557 - Classes de données suggère une alternative mutable.
Pour une fonctionnalité plus riche, vous pouvez essayer le paquet attrs
. Voir un exemple d'utilisation .
Il y a plusieurs façons d’atteindre cet objectif… .. Vous avez essentiellement besoin d’un objet extensible.
obj.a = type('Test', (object,), {})
obj.a.b = 'fun'
obj.b = lambda:None
class Test:
pass
obj.c = Test()
Maintenant, vous pouvez faire (pas sûr si c'est la même réponse que evilpie):
MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
Le module mock
est fondamentalement conçu pour cela.
import mock
obj = mock.Mock()
obj.a = 5
Essayez le code ci-dessous:
$ 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']
comme docs disent :
Note:
object
ne pas a un__dict__
, vous ne pouvez donc pas attribuer d'attributs arbitraires à une instance de la classeobject
.
Vous pouvez simplement utiliser une instance factice.
Vous pouvez également utiliser directement un objet de classe. cela crée un espace de noms:
class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')
Ces solutions sont très utiles lors des tests. En me basant sur les réponses de tous les autres, je le fais dans Python 2.7.9 (sans méthode statique, j'obtiens un TypeError (méthode non liée ...):
In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4
Si nous pouvons déterminer et regrouper tous les attributs et toutes les valeurs avant de créer l'objet imbriqué, nous pourrions créer une nouvelle classe qui prend un argument de dictionnaire lors de la création.
# python 2.7
class NestedObject():
def __init__(self, initial_attrs):
for key in initial_attrs:
setattr(self, key, initial_attrs[key])
obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'
Nous pouvons également autoriser les arguments de mots clés. Voir ce post .
class NestedObject(object):
def __init__(self, *initial_attrs, **kwargs):
for dictionary in initial_attrs:
for key in dictionary:
setattr(self, key, dictionary[key])
for key in kwargs:
setattr(self, key, kwargs[key])
obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')
J'arrive à cela tard dans la journée, mais voici mon pennyworth avec un objet qui contient des chemins utiles dans une application, mais vous pouvez l'adapter à tout ce qui vous intéresse. (ce qui est ce que je pense que cette question est vraiment):
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))
C'est cool parce que maintenant:
In [1]: x_path.projects
Out[1]: '/home/x/projects'
In [2]: x_path('caches')
Out[2]: '/home/x/caches'
Donc, ceci utilise l'objet fonction comme les réponses ci-dessus mais utilise la fonction pour obtenir les valeurs (vous pouvez toujours utiliser (getattr, x_path, 'repository')
plutôt que x_path('repository')
si vous préférez).
Quels objets utilisez-vous? J'ai juste essayé cela avec un exemple de classe et cela a bien fonctionné:
class MyClass:
i = 123456
def f(self):
return "hello world"
b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test
Et j'ai 123
comme réponse.
La seule situation où je vois cet échec est si vous essayez une setattr
sur un objet intégré.
Mise à jour: D'après le commentaire, il s'agit d'une répétition de: Pourquoi ne pouvez-vous pas ajouter d'attributs à un objet en python?