Supongamos que tengo una clase con un constructor (u otra función) que toma un número variable de argumentos y luego los establece como atributos de clase condicionalmente.
Podría configurarlos manualmente, pero parece que los parámetros variables son lo suficientemente comunes en Python que debería haber un lenguaje común para hacer esto. Pero no estoy seguro de cómo hacer esto de forma dinámica.
Tengo un ejemplo usando eval, pero eso no es seguro. Quiero saber la forma correcta de hacer esto, ¿tal vez con lambda?
class Foo:
def setAllManually(self, a=None, b=None, c=None):
if a!=None:
self.a = a
if b!=None:
self.b = b
if c!=None:
self.c = c
def setAllWithEval(self, **kwargs):
for key in **kwargs:
if kwargs[param] != None
eval("self." + key + "=" + kwargs[param])
pip install attrs
, decora tu clase con@attr.s
, y establece los argumentos comoa = attr.ib(); b = attr.ib()
etc. Lee más aquí .Respuestas:
Puede actualizar el
__dict__
atributo (que representa los atributos de la clase en forma de diccionario) con los argumentos de la palabra clave:entonces tú puedes:
y con algo como:
podría filtrar las claves de antemano (use en
iteritems
lugar deitems
si todavía está usando Python 2.x).fuente
self.__dict__.update(locals())
para copiar también argumentos posicionales.kwargs[0]
lugar de solokwargs
? ¿kwargs
Incluso puede tener una clave de número entero? Estoy bastante seguro de que tienen que ser cuerdas.Puedes usar el
setattr()
método:Existe un
getattr()
método análogo para recuperar atributos.fuente
.getattr()
? ¿O puedes acceder a los atributos conFoo.key
?Foo.attrname
. Creo que solo estaba señalando el hecho de que elgetattr
método existe. También es útil si desea proporcionar un valor predeterminado para cuando el atributo nombrado no está disponible.La mayoría de las respuestas aquí no cubren una buena manera de inicializar todos los atributos permitidos en un solo valor predeterminado. Entonces, para agregar a las respuestas dadas por @fqxp y @mmj :
fuente
False
. ¡Buen punto!Propongo una variación de la respuesta de fqxp , que, además de los atributos permitidos , le permite establecer valores predeterminados para los atributos:
Este es el código Python 3.x, para Python 2.x necesita al menos un ajuste,
iteritems()
en lugar deitems()
.fuente
Otra variante más basada en las excelentes respuestas de mmj y fqxp . ¿Y si queremos
Por "directamente", me refiero a evitar un
default_attributes
diccionario extraño .No es un gran avance, pero tal vez sea útil para alguien ...
EDITAR: Si nuestra clase usa
@property
decoradores para encapsular atributos "protegidos" con getters y setters, y si queremos poder establecer estas propiedades con nuestro constructor, es posible que deseemos expandir laallowed_keys
lista con valores dedir(self)
, como sigue:El código anterior excluye
dir()
(exclusión basada en la presencia de "__"), ydir()
cuyo nombre no se encuentre al final de un nombre de atributo (protegido o no) de__dict__.keys()
, por lo que probablemente solo se mantendrán los métodos decorados con @property.Es probable que esta edición solo sea válida para Python 3 y versiones posteriores.
fuente
Llamé a la clase
SymbolDict
porque esencialmente es un diccionario que opera usando símbolos en lugar de cadenas. En otras palabras, lo haces enx.foo
lugar de hacerlo,x['foo']
pero bajo las sábanas es realmente lo mismo.fuente
Las siguientes soluciones
vars(self).update(kwargs)
oself.__dict__.update(**kwargs)
no son robustas, porque el usuario puede ingresar a cualquier diccionario sin mensajes de error. Si necesito verificar que el usuario inserte la siguiente firma ('a1', 'a2', 'a3', 'a4', 'a5') la solución no funciona. Además, el usuario debería poder utilizar el objeto pasando los "parámetros posicionales" o los "parámetros de pares kay-valor".Así que sugiero la siguiente solución usando una metaclase.
fuente
Puede que sea una mejor solución, pero lo que me viene a la mente es:
fuente
este es el más fácil a través de larsks
mi ejemplo:
fuente
kwargs
es un diccionario de argumentos de palabras clave yitems()
es un método que devuelve una copia de la lista de(key, value)
pares del diccionario .Sospecho que podría ser mejor en la mayoría de los casos usar args con nombre (para un mejor código de autodocumentación), por lo que podría verse así:
fuente
for key, value in (a, b, c)