Python - 最有用的列表 - 理解构造

psi*_*lia -1 python list-comprehension list

Python的用户自制列表理解构造最有用吗?

我创建了以下两个量词,用于执行不同的验证操作:

def every(f, L): return not (False in [f(x) for x in L])
def some(f, L): return True in [f(x) for x in L]
Run Code Online (Sandbox Code Playgroud)

下面提出了一个优化版本(需要Python 2.5+):

def every(f, L): return all(f(x) for x in L)
def some(f, L): return any(f(x) for x in L) 
Run Code Online (Sandbox Code Playgroud)

那么,它是如何工作的?

"""For all x in [1,4,9] there exists such y from [1,2,3] that x = y**2"""
answer = every([1,4,9], lambda x: some([1,2,3], lambda y: y**2 == x))
Run Code Online (Sandbox Code Playgroud)

使用此类操作,您可以轻松地进行智能验证,例如:

"""There exists at least one bot in a room which has a life below 30%"""
answer = some(bots_in_this_room, lambda x: x.life < 0.3)
Run Code Online (Sandbox Code Playgroud)

等等,你可以使用这样的量词来回答甚至非常复杂的问题.当然,Python中没有无限的列表(嘿,它不是Haskell :)),但Python的列表理解非常实用.

你有自己喜欢的列表 - 理解结构吗?

PS:我想知道,为什么大多数人倾向于不回答问题而是批评所提出的例子?问题是关于最喜欢的列表 - 实际上是理解构造.

Mar*_*ers 13

any并且all是2.5的标准Python的一部分.没有必要制作自己的版本.如果可能的话,也是评估的正式版本anyall短路,从而提高性能.您的版本始终遍历整个列表.

如果你想要一个接受谓词的版本,可以使用类似于利用现有anyall函数的东西:

def anyWithPredicate(predicate, l): return any(predicate(x) for x in l) 
def allWithPredicate(predicate, l): return all(predicate(x) for x in l) 
Run Code Online (Sandbox Code Playgroud)

我并不特别看到需要这些功能,因为它实际上并没有节省太多的打字.

此外,使用您自己的具有相同名称但行为不同的函数隐藏现有标准Python函数是一种不好的做法.

  • @Bryan McLemore:"Predicate"不是一个.NET术语(当Anders Hjelsberg还是个孩子时,谓语在LISP中被使用),并且它也不是闭包的.NET术语. (3认同)
  • 你是不是在开玩笑吧?其中"谓词"的当前含义自19世纪以来一直在使用. (3认同)

Ale*_*lli 5

列表理解(简称LC)在很多情况下并不比等效的生成器表达式(简称GE,即使用圆括号而不是方括号)更有用,一次生成一个项目而不是而不是"一开始就全部散装").

有时你可以通过"投入"额外的内存来获得一点额外的速度,以便同时保存列表,这取决于在一个或另一个版本的Python上的优化和垃圾收集的变幻莫测,但这几乎不等于LC vs的实质性额外用途GE.

从本质上讲,与GE相比,为了从LC中获得大量的额外使用,您需要在序列上本质上需要"多次通过"的用例.在这种情况下,GE会要求您每次通过生成一次序列,而使用LC,您可以生成序列一次,然后对其执行多次传递(仅支付生成成本一次).如果GE/LC基于不易重启的底层迭代器(例如,实际上是Unix管道的"文件"),则多代也可能存在问题.

例如,假设您正在读取一个非空的打开文本文件f,其中有一堆(文本表示)数字由空格分隔(包括此处和那里的换行符,空行等).您可以使用GE将其转换为一系列数字:

G = (float(s) for line in f for s in line.split())
Run Code Online (Sandbox Code Playgroud)

或者LC:

L = [float(s) for line in f for s in line.split()]
Run Code Online (Sandbox Code Playgroud)

哪一个更好?取决于你正在做什么(即用例!).如果您想要的只是总和,则总和(G)和总和(L)也可以.如果你想要平均值,sum(L)/ len(L)对于列表是好的,但是对于生成器不起作用 - 考虑到"重新启动f"的困难,为了避免中间列表,你将不得不做类似的事情:

tot = 0.0
for i, x in enumerate(G): tot += x
return tot/(i+1)
Run Code Online (Sandbox Code Playgroud)

无处可见,快速,简洁和优雅return sum(L)/len(L).

请记住,sorted(G)确实返回一个列表(不可避免地),因此L.sort()(就地)在这种情况下是粗略的等价物 - 排序(L)将是超级的(因为现在你有两个列表).因此,当需要分类时,由于简洁,通常可以优选发电机.

总而言之,由于L是完全相同的list(G),所以很难对通过标点符号(方括号而不是圆括号)表达它的能力感到非常兴奋,而不是单个,简短,可发音和明显的单词,如list:-).这就是所有的LC - 基于标点符号的语法快捷方式list(some_genexp)......!