Pergunta

Eu quero converter o seguinte código:

...
urls = [many urls]
links = []
funcs = []
for url in urls:
   func = getFunc(url, links)
   funcs.append(func)
...

def getFunc(url, links):
   def func():
      page = open(url)
      link = searchForLink(page)
      links.append(link)
   return func

no código muito mais conveniente:

urls = [many urls]
links = []
funcs = []
for url in urls:
   <STATEMENT>(funcs):
        page = open(url)
        link = searchForLink(page)
        links.append(link)

Eu estava esperando para fazer isso com a declaração with. Como já comentado abaixo, eu estava esperando para conseguir:

def __enter__():
    def func():

..code in the for loop..

def __exit__():
  funcs.append(func)

Claro que isso não funciona.

compreensões lista não é bom para casos foram a searchForLink ação não é apenas uma função, mas muitas funções. Ele iria se transformar em um código extremamente ilegível. Por exemplo, mesmo que isso seria problemático com compreensões lista:

for url in urls:
  page = open(url)
  link1 = searchForLink(page)
  link2 = searchForLink(page)
  actionOnLink(link1)
  actionOnLink(link2)
  .... many more of these actions...
  links.append(link1)
Foi útil?

Solução

Um pouco convencional, mas você pode ter um decorador registrar o func e vincular qualquer variáveis ??de laço como argumentos padrão:

urls = [many urls]
links = []
funcs = []

for url in urls:
    @funcs.append
    def func(url=url):
        page = open(url)
        link = searchForLink(page)
        links.append(link)

Outras dicas

Não faz sentido usar with aqui. Em vez disso usar uma compreensão da lista:

funcs = [getFunc(url, links) for url in urls]

Existem apenas duas maneiras de criar funções: def e lambda. Lambdas são destinados a funções minúsculas, portanto, podem não ser muito apropriado para o seu caso. No entanto, se você realmente quiser, você pode colocar dois lambdas dentro do outro:

urls = [many urls]
links = []
funcs = [(lambda x:
            lambda:
              links.append(searchForLink(open(x))))(u)
         for u in urls]

Um pouco demasiado LISPish para o meu gosto.

Perder o <STATEMENT>(funcs): linha

Editar:

Quer dizer: por que você faria isso? Por que definir uma função nova para cada página? Porque não basta fazer isso?

urls = [many urls]
links = []
for url in urls:
    page = open(url)
    link = searchForLink(page)
    links.append(link) 

Você não deve usar "com" para fazer isso (embora, dado que é Python, você quase certamente poderia, usando algum efeito colateral bizarro e dynamicism do Python).

A propósito de "com" em Python é, como descrito na os docs "para envolver a execução de um bloco com métodos definidos por um gerente de contexto. Isto permite tentativa comum ... exceto ... finalmente padrões de uso para serem encapsulados para reutilização conveniente."

Eu acho que você está confundindo nofollow do Python "com" com o Javascript / VisualBasic "com", que pode ser cosmeticamente semelhante, mas que é efetivamente independentes.

O bom e velho itertools .

from itertools import imap
links.extend(imap(searchForLink, imap(open, urls)))

Embora, talvez você prefira funcional.

from functional import *
funcs = [partial(compose(compose(links.append, searchForLink), open), url) for url in urls]
for func in funcs: func()

Eu não acho que vale a pena criar uma classe para uso with:. É mais trabalho para criar __enter__ e __exit__ do que está a apenas escrever uma função auxiliar

Você pode ser melhor usando geradores para alcançar o cálculo atraso que você está depois.

def MakeLinks(urls):
    for url in urls:
        page = open(url)
        link = searchForLink(page)
        yield link

links = MakeLinks(urls)

Quando você quiser que os links:

for link in links:
    print link

Os urls será olhou para cima durante este ciclo, e não todos de uma vez (que parece que você está tring para evitar).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top