Python:使用“with”动态定义新函数

时间:2010-02-04 13:41:01

标签: python with-statement

我想转换以下代码:

...
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

进入更方便的代码:

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

我希望用with语句来做这件事。正如我评论的那样,我希望能够实现:

def __enter__():
    def func():

..code in the for loop..

def __exit__():
  funcs.append(func)

当然这不起作用。

如果行为searchForLink不仅仅是一个功能而是许多功能,那么列表理解对于案例并不好。它将变成一个非常难以理解的代码。例如,即使这对列表推导也有问题:

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)

7 个答案:

答案 0 :(得分:6)

在这里使用with是没有意义的。而是使用列表理解:

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

答案 1 :(得分:4)

有点不同寻常,但你可以让装饰器注册func并将任何循环变量绑定为默认参数:

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

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

答案 2 :(得分:2)

丢掉第<STATEMENT>(funcs):

编辑:

我的意思是:你为什么要这样做?为什么要为每个页面定义一个新功能?为什么不这样做?

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

答案 3 :(得分:2)

创建函数的方法只有两种:deflambda。 Lambda用于小功能,因此它们可能不适合您的情况。但是,如果你真的想要,你可以将两个lambda包含在一起:

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

根据我的口味,有点太偏心了。

答案 4 :(得分:1)

你不应该使用“with”来做这件事(尽管,考虑到它是Python,你几乎可以肯定,使用一些奇怪的副作用和Python的动态主义)。

Python中“with”的目的是as described in the docs,“用上下文管理器定义的方法包装块的执行。这允许常见的尝试...除了...最终的使用模式被封装以便于重复使用。“

我认为你把Python的“with”与Javascript / VisualBasic“与”混淆,这可能在美容上相似,但实际上是无关的。

答案 5 :(得分:1)

好老itertools

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

虽然,也许你更喜欢functional

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

我认为为with使用创建一个类是不值得的:创建__enter____exit__比创建一个帮助函数要多得多。

答案 6 :(得分:1)

您可能最好使用生成器来实现您所追求的延迟计算。

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

links = MakeLinks(urls)

如果您需要链接:

for link in links:
    print link

在这个循环期间会查找网址,而不是一次全部查找(看起来你似乎要避免)。