Suponha que eu tenha uma classe com um construtor (ou outra função) que recebe um número variável de argumentos e os define como atributos de classe condicionalmente.
Eu poderia defini-los manualmente, mas parece que os parâmetros variáveis são comuns o suficiente em python que deve haver um idioma comum para fazer isso. Mas não tenho certeza de como fazer isso dinamicamente.
Eu tenho um exemplo usando eval, mas dificilmente é seguro. Quero saber a maneira correta de fazer isso - talvez com 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
, decore sua classe com@attr.s
e defina os argumentos comoa = attr.ib(); b = attr.ib()
etc. Leia mais aqui .Respostas:
Você pode atualizar o
__dict__
atributo (que representa os atributos da classe na forma de um dicionário) com os argumentos de palavra-chave:então você pode:
e com algo como:
você pode filtrar as chaves de antemão (use em
iteritems
vez deitems
se ainda estiver usando o Python 2.x).fonte
self.__dict__.update(locals())
para copiar também argumentos posicionais.kwargs[0]
vez de apenaskwargs
? Podekwargs
até ter uma chave inteira? Tenho certeza de que devem ser cordas.Você pode usar o
setattr()
método:Existe um
getattr()
método análogo para recuperar atributos.fonte
.getattr()
? Ou você pode acessar os atributos comFoo.key
?Foo.attrname
. Acho que estava apenas apontando o fato de que ogetattr
método existe. Também é útil se você deseja fornecer um valor padrão para quando o atributo nomeado não estiver disponível.A maioria das respostas aqui não cobre uma boa maneira de inicializar todos os atributos permitidos com apenas um valor padrão. Então, para adicionar às respostas dadas por @fqxp e @mmj :
fonte
False
. Bom ponto!Proponho uma variação da resposta de fqxp , que, além dos atributos permitidos , permite definir valores padrão para os atributos:
Este é o código Python 3.x, para Python 2.x você precisa de pelo menos um ajuste,
iteritems()
no lugar deitems()
.fonte
Mais uma variante baseada nas excelentes respostas de mmj e fqxp . E se quisermos
Por "diretamente", quero dizer evitar um
default_attributes
dicionário estranho .Não é um grande avanço, mas talvez útil para alguém ...
EDITAR: Se nossa classe usa
@property
decoradores para encapsular atributos "protegidos" com getters e setters, e se queremos ser capazes de definir essas propriedades com nosso construtor, podemos expandir aallowed_keys
lista com valores dedir(self)
, como segue:O código acima exclui
dir()
(exclusão com base na presença de "__"), edir()
cujo nome não seja encontrado no final de um nome de atributo (protegido ou não) de__dict__.keys()
, provavelmente mantendo apenas os métodos decorados com @property.Esta edição provavelmente só é válida para Python 3 e superior.
fonte
Chamei a classe
SymbolDict
porque é essencialmente um dicionário que opera usando símbolos em vez de strings. Em outras palavras, você faz emx.foo
vez de,x['foo']
mas por trás das cobertas, é realmente a mesma coisa acontecendo.fonte
As seguintes soluções
vars(self).update(kwargs)
ouself.__dict__.update(**kwargs)
não são robustas, pois o usuário pode entrar em qualquer dicionário sem mensagens de erro. Se eu precisar verificar se o usuário insere a seguinte assinatura ('a1', 'a2', 'a3', 'a4', 'a5') a solução não funciona. Além disso, o usuário deve ser capaz de usar o objeto passando os "parâmetros posicionais" ou os "parâmetros dos pares de valor kay".Portanto, sugiro a seguinte solução usando uma metaclasse.
fonte
Pode ser uma solução melhor, mas o que me vem à mente é:
fonte
este é o mais fácil via larsks
meu exemplo:
fonte
kwargs
é um dicionário de argumentos de palavra-chave eitems()
é um método que retorna uma cópia da lista de(key, value)
pares do dicionário .Suspeito que seja melhor na maioria dos casos usar args nomeados (para um melhor código de autodocumentação), então pode ser algo assim:
fonte
for key, value in (a, b, c)