Estou usando a classe a seguir para armazenar facilmente dados das minhas músicas.
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
Eu sinto que isso é muito mais extensível do que escrever um if/else
bloco. No entanto, eval
parece ser considerado uma prática ruim e insegura de usar. Nesse caso, alguém pode me explicar o porquê e me mostrar uma maneira melhor de definir a classe acima?
exec/eval
e ainda não sabiasetattr
?Respostas:
Sim, usar eval é uma prática ruim. Apenas para citar alguns motivos:
No seu caso, você pode usar o setattr :
EDITAR:
Existem alguns casos em que você precisa usar eval ou exec. Mas eles são raros. Usar eval no seu caso é uma prática ruim, com certeza. Estou enfatizando as más práticas, porque eval e exec são frequentemente usados no lugar errado.
EDIT 2:
Parece que alguns discordam de que avaliação é 'muito perigosa e insegura' no caso do OP. Isso pode ser verdade para este caso específico, mas não em geral. A pergunta era geral e as razões que listei também são verdadeiras para o caso geral.
EDIT 3: Reordenados pontos 1 e 4
fonte
eval
não tem nada a ver um com o outro. Um aplicativo que é fundamentalmente mal projetado é fundamentalmente mal projetado.eval
não é mais a causa raiz do mau design do que a divisão por zero ou a tentativa de importar um módulo que se sabe não existir.eval
não é inseguro. Os aplicativos são inseguros.calc
e, para adicionar números, ele executaprint(eval("{} + {}".format(n1, n2)))
e sai. Agora você distribui este programa com algum sistema operacional. Alguém cria um script bash que pega alguns números de um site de ações e os adiciona usandocalc
. estrondo?O uso
eval
é fraco, não é uma prática claramente ruim .Ele viola o "Princípio Fundamental do Software". Sua fonte não é a soma total do que é executável. Além da sua fonte, existem argumentos para
eval
, que devem ser claramente entendidos. Por esse motivo, é a ferramenta de último recurso.Geralmente é um sinal de design impensado. Raramente existe uma boa razão para o código-fonte dinâmico, criado on-the-fly. Quase tudo pode ser feito com delegação e outras técnicas de design de OO.
Isso leva a uma compilação on-the-fly relativamente lenta de pequenos pedaços de código. Uma sobrecarga que pode ser evitada usando melhores padrões de design.
Como nota de rodapé, nas mãos de sociopatas enlouquecidos, pode não funcionar bem. No entanto, quando confrontados com usuários ou administradores sociopatas enlouquecidos, é melhor não dar a eles o Python interpretado em primeiro lugar. Nas mãos do verdadeiro mal, Python pode ser um passivo;
eval
não aumenta o risco.fonte
eval
é algum tipo de "vulnerabilidade de segurança". Como se o Python - por si só - não fosse apenas um monte de fontes interpretadas que alguém pudesse modificar. Quando confrontado com o "eval é uma falha de segurança", você pode apenas assumir que é uma falha de segurança nas mãos dos sociopatas. Programadores comuns apenas modificam a fonte Python existente e causam seus problemas diretamente. Não indiretamente através daeval
magia.while True: pass
seria difícil limpar com algum tipo de fuga.eval()
, pois é uma string. Código do "mundo exterior" não pode ser higienizado. Cordas do mundo exterior são apenas cordas. Não sei ao certo o que você está falando. Talvez você deva fornecer uma postagem de blog mais completa e link para ela aqui.Nesse caso sim. Ao invés de
você deve usar o builtin função
setattr
:fonte
Sim, ele é:
Corte usando Python:
O código abaixo listará todas as tarefas em execução em uma máquina Windows.
No Linux:
fonte
Vale ressaltar que, para o problema específico em questão, existem várias alternativas ao uso
eval
:O mais simples, como observado, está usando
setattr
:Uma abordagem menos óbvia é atualizar o objeto do
__dict__
objeto diretamente. Se tudo o que você deseja fazer é inicializar os atributosNone
, isso é menos direto do que o descrito acima. Mas considere isso:Isso permite que você passe argumentos de palavras-chave para o construtor, por exemplo:
Também permite que você use
locals()
mais explícito, por exemplo:... e, se você realmente deseja atribuir
None
aos atributos cujos nomes são encontrados emlocals()
:Outra abordagem para fornecer um objeto com valores padrão para uma lista de atributos é definir o
__getattr__
método da classe :Este método é chamado quando o atributo nomeado não é encontrado da maneira normal. Essa abordagem é um pouco menos direta do que simplesmente definir os atributos no construtor ou atualizar o
__dict__
, mas tem o mérito de não criar o atributo, a menos que ele exista, o que pode reduzir substancialmente o uso de memória da classe.O ponto de tudo isso: em geral, existem muitas razões para evitar
eval
- o problema de segurança da execução de código que você não controla, o problema prático de código que você não pode depurar etc. etc. Mas uma razão ainda mais importante é que geralmente você não precisa usá-lo. O Python expõe tanto de seus mecanismos internos ao programador que você raramente precisa escrever um código que escreva código.fonte
__dict__
diretamente o objeto, forneça ao objeto um objeto de dicionário real, por herança ou como um atributo.__setattr__
substituição, o que pode levar a resultados inesperados.setattr()
não tem esse problema.Outros usuários apontaram como seu código pode ser alterado para não depender
eval
; Vou oferecer um caso de uso legítimo para usoeval
, encontrado mesmo no CPython: testing .Aqui está um exemplo que encontrei em
test_unary.py
que um teste para determinar se(+|-|~)b'a'
gera umTypeError
:O uso claramente não é uma má prática aqui; você define a entrada e apenas observa o comportamento.
eval
é útil para teste.Dê uma olhada esta pesquisa para
eval
, realizada no repositório git CPython; o teste com eval é muito usado.fonte
Quando
eval()
é usado para processar a entrada fornecida pelo usuário, você habilita o usuário a soltar para o REPL fornecendo algo como isto:Você pode se safar, mas normalmente não deseja vetores para execução arbitrária de código em seus aplicativos.
fonte
Além da resposta da @Nadia Alramli, como eu sou novo no Python e estava ansioso para verificar como o uso
eval
afetaria os horários , tentei um pequeno programa e abaixo as observações:fonte