在python列表中添加额外语句

在python列表中添加额外语句,python,list-comprehension,Python,List Comprehension,我需要在文本文件中找到一行,该行包含一个特定的字符串,然后将该行及其后面的所有行附加到列表中。我就是这样完成的 file1 = open("input.txt", "r") always_print = False lines = file1.readlines() output = [] for line in lines: if always_print or "def set" in line: #def set is the string i want outp

我需要在文本文件中找到一行,该行包含一个特定的字符串,然后将该行及其后面的所有行附加到列表中。我就是这样完成的

file1 = open("input.txt", "r")
always_print = False
lines = file1.readlines()
output = []
for line in lines:
    if always_print or "def set" in line:  #def set is the string i want
        output.append(line)
        always_print = True
虽然这很好,但我尝试使用列表理解来做同样的事情。这就是我得到的:

lines = [ item.strip() for item in open("input.txt")]
always_print = False
output = [item for item in lines if "def set" or print_always in item]

这显然不起作用,因为当找到所需的字符串时,我没有设置always_print=True。我如何在列表中做到这一点

编辑更正我之前完全不正确的答案:

这并不是说我会在生产代码中使用它,而是黑客攻击它,你可以在列表中使用它

always_print = []
output = [item for item in lines 
          if always_print
          or (always_print.append(1) if ("def set" in item) else None) 
          or "def set" in item]
只是解释一下,三个条件中的第二个总是返回
None
,这是一个错误的值

如果您不想对项目中的“def set”进行两次评估,请进一步滑入黑暗面:

always_print = []
output = [item for item in lines 
          if always_print
          or (
              (always_print.append(1) or True) if ("def set" in item) else False
             )]
Edit2

如果我更详细地描述这里发生的事情

上面的代码(以及凯文在评论中提到的代码)使用了三种不同的技巧

  • 在Python中,大多数对象和值都有关联的布尔值。e、 g.0为
    False
    ,任何其他数字为
    True
    。同样,空列表为
    False
    ,而非空列表的计算结果为
    True
  • 虽然像a=1这样的变量赋值不返回任何值,并且不能作为列表理解的一部分包含在内,
    a_list.append(x)
    是一个函数调用,返回
    None
    ,其计算结果为
    False
    。它还有一个副作用,就是将新元素
    x
    添加到
    a_列表的末尾
  • 这样的逻辑运算符的求值顺序是从左到右
    在第一个
    False
    值处停止执行,而
    在第一个
    True
    值处停止执行,可用于根据特定条件控制是否执行列表追加。三元运算符“x if y else z”也有求值顺序,但先求值“y”,然后求值“x”或“z”,但决不能同时求值
  • 正如您所看到的,一组非常迂回的逻辑技巧可能在超优化的C(或)中占有一席之地,但在Python中却没有。可以在列表理解中复制控制流,但实际上,每次都要使用
    dropwhile

    用于查找包含
    def集合的第一行:

    from itertools import dropwhile
    
    output = list(dropwhile(lambda l: 'def set' not in l, lines))
    
    dropwhile()
    将跳过
    行中与测试不匹配的任何条目;一旦匹配,它就会停止测试,并简单地从那里产生所有结果

    dropwhile()
    返回迭代器;我在这里使用了
    list()
    将其转换为行列表,但您也可以将其用作另一个循环的基础,如换行符的剥离等

    演示:


    中途退出可能是最好的解决方案。但是,如果你想要一些真正别致的东西,请看以下内容:

    使用列表理解,您可以使用简单的检查和转换,但您应该看到列表理解更像一个数学映射。但是,您可以将用于测试某个项目是否应包含在某种状态中的函数指定为某种状态,即让您的检查记住是否已经发生了某些事情。使其成为函子(或函数对象):

    哪些产出:

    [6, 7, 8, 9]
    [4, 5, 6, 7, 8, 9]
    

    @说实话,我只是读了一下
    output=…
    行…你不能把句子(比如你的作业
    always\u print=True
    )放在列表理解中。那么这会像原始代码那样在循环中修改
    always\u print
    值吗?有趣的方法。我的想法是一样的:
    output=[line for line in line如果总是打印或“def set”in line而不是总是打印。append(1)]
    。使用大致相同的“条件突变”原理。啊,这更优雅,以一种黑暗的方式。凯文和森普拉德..试图理解..总是打印。附加(1)做什么?“打印”是否始终不是布尔值?我们可以像列表一样附加到它吗?这真的很好。这正是我所需要的。所以,为了理解,我可以得出结论,python不支持列表理解中的额外语句吗?@Amistad Correct。列表理解是一个表达式,任何表达式都不能包含语句。@Amistad:在Python中,列表理解是一个表达式。表达式可以任意嵌套,但语句是顶级组件,不能嵌套在彼此内部或表达式中。赋值是一个语句,您不能在表达式中使用它。@Amistad:您必须使用另一个可变对象,它的状态可以通过方法更改,但很快就会变糟。这里,一个
    dropwhile()
    更好地表达了发生的事情。
    class Drop_before:
      def __init__(self, val):
        self.val = val
        self.always_print = False
      def __call__(self, current_val):
        if current_val == self.val:
          self.always_print = True
        return self.always_print
    
    drop_before_6 = Drop_before(6)
    print [x for x in xrange(10) if drop_before_6(x)]
    #using filter
    print filter(Drop_before(4), xrange(10))
    
    [6, 7, 8, 9]
    [4, 5, 6, 7, 8, 9]