Sinto muito se essa é uma pergunta absolutamente sofisticada, mas estou curiosa para saber quais são as melhores práticas e não consigo encontrar uma boa resposta no Google.
Em Python, eu costumo usar uma classe vazia como um contêiner de estrutura de dados com capacidade super grande (como um arquivo JSON) e adicionar atributos ao longo do caminho:
class DataObj:
"Catch-all data object"
def __init__(self):
pass
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Isso me dá uma tremenda quantidade de flexibilidade, porque o objeto contêiner pode essencialmente armazenar qualquer coisa. Portanto, se novos requisitos surgirem, vou adicioná-lo como outro atributo ao objeto DataObj (que passo em meu código).
No entanto, recentemente me impressionou (por programadores de FP) que essa é uma prática terrível, porque torna muito difícil a leitura do código. É preciso passar por todo o código para descobrir quais atributos o DataObj realmente possui.
Pergunta : Como posso reescrever isso para maior facilidade de manutenção sem sacrificar a flexibilidade?
Há alguma idéia da programação funcional que eu possa adotar?
Estou procurando as melhores práticas por aí.
Nota : uma idéia é pré-inicializar a classe com todos os atributos que se espera encontrar, por exemplo
class DataObj:
"Catch-all data object"
def __init__(self):
data.a = 0
data.b = ""
data.c = []
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Isso é realmente uma boa ideia? E se eu não souber quais são meus atributos a priori?
Respostas:
Você não A flexibilidade é precisamente o que causa o problema. Se qualquer código em qualquer lugar pode alterar os atributos de um objeto, a manutenção já está em pedaços. Idealmente, toda classe tem um conjunto de atributos que são definidos como pedra depois
__init__
e o mesmo para cada instância. Nem sempre é possível ou sensato, mas deve ser o caso sempre que você não tiver realmente boas razões para evitá-lo.Isso não é uma boa idéia. Claro, o atributo está lá, mas pode ter um valor falso, ou mesmo válido, que encobre o código que não atribui o valor (ou um erro de ortografia).
AttributeError
é assustador, mas obter resultados errados é pior. Os valores padrão em geral são bons, mas para escolher um padrão adequado (e decidir o que é necessário), é necessário saber para que o objeto é usado.Então você está ferrado em qualquer caso e deve usar um dict ou lista em vez de nomes de atributos codificados. Mas suponho que você quis dizer "... no momento em que escrevo a classe do contêiner". Em seguida, a resposta é: "Você pode editar arquivos em passo de bloqueio, duh". Precisa de um novo atributo? Adicione um atributo de frigging à classe de contêiner. Há mais código usando essa classe e ele não precisa desse atributo? Considere dividir as coisas em duas classes separadas (use mixins para permanecer SECO), portanto, faça isso opcional se fizer sentido.
Se você tem medo de escrever aulas de contêineres repetitivas: aplique metaprogramação criteriosamente ou use-o
collections.namedtuple
se não precisar alterar os membros após a criação (seus amigos do FP ficariam satisfeitos).fonte
Você sempre pode usar a aula de Alex Martelli . No seu caso:
Dessa forma, pelo menos fica claro para o leitor que os dados são apenas um armazenamento de dados estúpidos e é possível ver imediatamente quais valores são armazenados sob o nome, pois tudo acontece em uma linha.
E sim, fazer as coisas dessa maneira é de fato uma boa ideia, às vezes.
fonte
Eu provavelmente usaria a segunda abordagem, possivelmente usando
None
para indicar dados inválidos. É verdade que é difícil ler / manter se você adicionar atributos posteriormente. No entanto, mais informações sobre o objetivo dessa classe / objeto forneceriam informações sobre por que a primeira idéia é um projeto ruim: onde você teria uma classe completamente vazia sem métodos ou dados padrão? Por que você não sabe quais atributos a classe possui?É possível que
processData
isso seja melhor como método (process_data
para seguir as convenções de nomenclatura de python), pois ele atua na classe. Dado o exemplo, parece que poderia ser melhor como uma estrutura de dados (onde adict
pode ser suficiente).Dado um exemplo real, você pode levar a questão para o CodeReview , onde eles podem ajudar a refatorar o código.
fonte