Estruturação de um programa.Classes e funções em Python
-
21-09-2019 - |
Pergunta
Estou escrevendo um programa que usa técnicas genéticas para evoluir equações.Quero poder enviar a função 'mainfunc' para a função 'submit' do Parallel Python.A função 'mainfunc' chama dois ou três métodos definidos na classe Utility.Eles instanciam outras classes e chamam vários métodos.Acho que o que quero é tudo isso em um NAMESPACE.Então, instanciei algumas (talvez devessem ser todas) das classes dentro da função 'mainfunc'.Eu chamo o método Utility de 'generate()'.Se seguissemos sua cadeia de execução, isso envolveria todas as classes e métodos no código.
Agora, as equações são armazenadas em uma árvore.Cada vez que uma árvore é gerada, mutada ou criada, os nós precisam receber uma nova chave para que possam ser acessados a partir de um atributo de dicionário da árvore.A classe 'KeySeq' gera essas chaves.
No Parallel Python, enviarei várias instâncias de 'mainfunc' para a função 'submit' do PP.Cada um deve ser capaz de acessar o 'KeySeq'.Seria bom se todos acessassem a mesma instância do KeySeq para que nenhum dos nós nas árvores retornadas tivesse a mesma chave, mas eu poderia contornar isso, se necessário.
Então:minha pergunta é sobre colocar TUDO no mainfunc.Obrigado (editar) Se eu não incluir tudo no MainFunc, tenho que tentar contar ao PP sobre funções dependentes, etc, passando vários argumentos em vários lugares.Estou tentando evitar isso.
(edição tardia) se ks.next() for chamado dentro da função 'generate(), ele retornará o erro 'NameError:o nome global 'ks' não está definido'
class KeySeq:
"Iterator to produce sequential \
integers for keys in dict"
def __init__(self, data = 0):
self.data = data
def __iter__(self):
return self
def next(self):
self.data = self.data + 1
return self.data
class One:
'some code'
class Two:
'some code'
class Three:
'some code'
class Utilities:
def generate(x):
'___________'
def obfiscate(y):
'___________'
def ruminate(z):
'__________'
def mainfunc(z):
ks = KeySeq()
one = One()
two = Two()
three = Three()
utilities = Utilities()
list_of_interest = utilities.generate(5)
return list_of_interest
result = mainfunc(params)
Solução
Se você quiser todas as instâncias de mainfunc
usar o mesmo KeySeq
objeto, você pode usar o truque do valor do parâmetro padrão:
def mainfunc(ks=KeySeq()):
key = ks.next()
Contanto que você realmente não passe um valor de ks
, todas as chamadas para mainfunc
usará a instância de KeySeq
que foi criado quando a função foi definida.
Aqui está o porquê, caso você não saiba:Uma função é um objeto.Tem atributos.Um de seus atributos é denominado func_defaults
;é uma tupla contendo os valores padrão de todos os argumentos em sua assinatura que possuem padrões.Quando você chama uma função e não fornece um valor para um argumento que possui um padrão, a função recupera o valor de func_defaults
.Então, quando você ligar mainfunc
sem fornecer um valor para ks
, obtém o KeySeq()
instância fora do func_defaults
tupla.O que, para esse caso de mainfunc
, é sempre o mesmo KeySeq
instância.
Agora, você diz que vai enviar "múltiplas instâncias de mainfunc
para o submit
função do PP." Você realmente quer dizer múltiplas instâncias?Nesse caso, o mecanismo que estou descrevendo não funcionará.
Mas é complicado criar múltiplas instâncias de uma função (e o código que você postou não cria).Por exemplo, esta função retorna uma nova instância de g
toda vez que é chamado:
>>> def f():
def g(x=[]):
return x
return g
>>> g1 = f()
>>> g2 = f()
>>> g1().append('a')
>>> g2().append('b')
>>> g1()
['a']
>>> g2()
['b']
Se eu ligar g()
sem argumento, ele retorna o valor padrão (inicialmente uma lista vazia) de seu func_defaults
tupla.Desde g1
e g2
são instâncias diferentes do g
função, seu valor padrão para o x
argumento é também uma instância diferente, que o acima demonstra.
Se você quiser tornar isso mais explícito do que usar um efeito colateral complicado de valores padrão, aqui está outra maneira de fazer isso:
def função principal():se não for hasattr(mainfunc, "ks"):setAtTr (mainfunc, "ks", keyseq ()) key = mainfunc.ks.next ()
Por fim, um ponto super importante que o código que você postou ignora:Se você pretende fazer processamento paralelo em dados compartilhados, o código que toca esses dados precisa implementar o bloqueio.Olhe para a callback.py
exemplo na documentação do Parallel Python e veja como o bloqueio é usado no Sum
aula e por quê.
Outras dicas
Não há problema em estruturar seu programa dessa maneira.Muitos utilitários de linha de comando seguem o mesmo padrão:
#imports, utilities, other functions
def main(arg):
#...
if __name__ == '__main__':
import sys
main(sys.argv[1])
Dessa forma você pode ligar para o main
função de outro módulo importando-o ou você pode executá-lo a partir da linha de comando.
Seu conceito de classes em Python não é bom, eu acho.Talvez fosse uma boa ideia revisar o básico.Este link ajudará.