python - privados - ¿Cómo puedo crear un objeto y agregarle atributos?
self python 3 (16)
¿Qué objetos estás usando? Solo probé eso con una clase de muestra y funcionó bien:
class MyClass:
i = 123456
def f(self):
return "hello world"
b = MyClass()
b.c = MyClass()
setattr(b.c, ''test'', 123)
b.c.test
Y tengo 123
como respuesta.
La única situación en la que veo que este fallo es si estás probando un setattr
en un objeto incorporado.
Actualización: Del comentario, esto es una repetición de: ¿Por qué no puedes agregar atributos al objeto en Python?
Quiero crear un objeto dinámico (dentro de otro objeto) en Python y luego agregarle atributos.
Lo intenté:
obj = someobject
obj.a = object()
setattr(obj.a, ''somefield'', ''somevalue'')
pero esto no funcionó.
¿Algunas ideas?
editar:
Estoy configurando los atributos de un bucle for
que recorre una lista de valores, por ejemplo
params = [''attr1'', ''attr2'', ''attr3'']
obj = someobject
obj.a = object()
for p in params:
obj.a.p # where p comes from for loop variable
En el ejemplo anterior obtendría obj.a.attr1
, obj.a.attr2
, obj.a.attr3
.
Utilicé la función setattr
porque no sabía cómo hacer obj.a.NAME
desde un bucle for
.
¿Cómo establecería el atributo según el valor de p
en el ejemplo anterior?
Ahora puedes hacerlo (no estoy seguro de si es la misma respuesta que evilpie):
MyObject = type(''MyObject'', (object,), {})
obj = MyObject()
obj.value = 42
De otra manera veo, de esta manera:
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)
El object
incorporado puede ser instanciado pero no puede tener ningún atributo establecido en él. (Ojalá pudiera, para este propósito exacto). No tiene un __dict__
para mantener los atributos.
Generalmente solo hago esto:
class Object(object):
pass
a = Object()
a.somefield = somevalue
Cuando puedo, le doy a la clase Object
un nombre más significativo, dependiendo de qué tipo de datos estoy ingresando.
Algunas personas hacen una cosa diferente, donde usan una subclase de dict
que permite el acceso de atributos para obtener las claves. ( d.key
lugar de d[''key'']
)
Editar : Para agregar a su pregunta, usar setattr
está bien. Simplemente no puede usar setattr
en setattr
de object()
.
params = [''attr1'', ''attr2'', ''attr3'']
for p in params:
setattr(obj.a, p, value)
El módulo mock
está hecho básicamente para eso.
import mock
obj = mock.Mock()
obj.a = 5
Está todo en los docs .
TLDR: necesitas hacer valer la propiedad return_value
del simulacro, el resto es ''Magic''.
Ejemplo:
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!'')
Estas soluciones son muy útiles durante las pruebas. Sobre la base de las respuestas de todos los demás, hago esto en Python 2.7.9 (sin el método estático, obtengo un TypeError (método no vinculado ...):
In [11]: auth = type('''', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4
Hay clases de types.SimpleNamespace
en Python 3.3+ :
obj = someobject
obj.a = SimpleNamespace()
for p in params:
setattr(obj.a, p, value)
# obj.a.attr1
collections.namedtuple
, typing.NamedTuple
podría usarse para objetos inmutables. PEP 557 - Clases de datos sugiere una alternativa mutable.
Para una funcionalidad más rica, puede probar el paquete attrs
. Ver un ejemplo de uso .
Hay algunas maneras de alcanzar este objetivo. Básicamente necesitas un objeto que sea extensible.
obj.a = type(''Test'', (object,), {})
obj.a.b = ''fun''
obj.b = lambda:None
class Test:
pass
obj.c = Test()
Llegando a esta hora avanzada, pero aquí está mi pennyworth con un objeto que por casualidad contiene algunas rutas útiles en una aplicación, pero puede adaptarlo para cualquier cosa en la que desee una cierta cantidad de información a la que pueda acceder con getattr y la notación de puntos. (que es de lo que creo que se trata realmente esta pregunta):
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))
Esto es genial porque ahora:
In [1]: x_path.projects
Out[1]: ''/home/x/projects''
In [2]: x_path(''caches'')
Out[2]: ''/home/x/caches''
Por lo tanto, utiliza el objeto de función como las respuestas anteriores, pero usa la función para obtener los valores (aún puede usar (getattr, x_path, ''repository'')
lugar de x_path(''repository'')
si lo prefiere).
Podría usar mi antigua receta de Bunch , pero si no desea crear una "clase de manojo", ya existe una muy simple en Python: todas las funciones pueden tener atributos arbitrarios (incluidas las funciones lambda). Así, los siguientes trabajos:
obj = someobject
obj.a = lambda: None
setattr(obj.a, ''somefield'', ''somevalue'')
Si la pérdida de claridad en comparación con la venerable receta de Bunch
está bien, es una decisión de estilo que, por supuesto, le dejaré a usted.
Pruebe el siguiente código:
$ 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'']
Si podemos determinar y agregar todos los atributos y valores juntos antes de crear el objeto anidado, entonces podríamos crear una nueva clase que tome un argumento de diccionario en la creación.
# 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''
También podemos permitir argumentos de palabras clave. Ver este 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'')
También puedes usar un objeto de clase directamente; crea un espacio de nombres:
class a: pass
a.somefield1 = ''somevalue1''
setattr(a, ''somefield2'', ''somevalue2'')
como dicen los doctores :
Nota : el
object
no tiene un__dict__
, por lo que no puede asignar atributos arbitrarios a una instancia de la clase deobject
.
Puedes usar una instancia de clase ficticia.
di = {}
for x in range(20):
name = ''_id%s'' % x
di[name] = type(name, (object), {})
setattr(di[name], "attr", "value")