title: How to create a generator that brings specific, unrelated lazily evaluated expressions
body: <p>Discovered this after discovering the all( ) function in Python doesn't shortcircuit as I expect because the expressions inside the list you send are not lazily evaluated. So:</p>
  <pre class="lang-py prettyprint-override"><code>all([
      previous_task is not None,
      self.task_type == previous_task.task_type,
      self.owner is None,
      previous_task.owner is None,
      self.is_sibling_of(previous_task)
      ])
  </code></pre>
  <p>In this code for example, if previous_task is None, <code>self.task_type == previous_task.task_type</code> will still evaluate and throw an Exception while trying to access previous_task.task_type</p>
  <p>Although this is easily fixable like this (and actually shortcircuits AND is lazy):</p>
  <pre class="lang-py prettyprint-override"><code>previous_task is not None and all([ 
      self.task_type == previous_task.task_type,
      self.owner is None,
      previous_task.owner is None,
      self.is_sibling_of(previous_task)
      ])
  </code></pre>
  <p>The core problem actually lies in that the list expression will evaluate the code inside eagerly while creating it.</p>
  <p>So the solution is to create a generator, so it actually only evaluates the item one by one. But... generators require a comprenhension from something to actually generate. Or a function with the yield argument.</p>
  <p>And although I could do something like this:</p>
  <pre class="lang-py prettyprint-override"><code>def __evaluate(self, previous_task):
      yield previous_task is not None
      yield self.task_type == previous_task.task_type
      yield self.owner is None
      yield previous_task.owner is None
      yield self.is_sibling_of(previous_task)
  </code></pre>
  <p>Readability suffers, defeating the purpose of <code>all</code>.</p>
  <p>And I found on the PEP that you can use something like this:</p>
  <pre class="lang-py prettyprint-override"><code>(condition 
      for evaluation 
      in (
          previous_task is not None,
          self.task_type == previous_task.task_type,
          self.owner is None,
          previous_task.owner is None,
          self.is_sibling_of(previous_task)
      )
  )
  </code></pre>
  <p>That wont work either, because the second parentheses is a set literal, not a generator, and it will evaluate the contents of the set on construction just like the list.</p>
  <p>Another option is to make a reduce argument, from a list of lambdas, like this:</p>
  <pre class="lang-py prettyprint-override"><code>reduce(
      lambda actual, next_function: actual and next_function(),
      [
          lambda: previous_task is not None
          lambda: self.task_type == previous_task.task_type
          lambda: self.owner is None
          lambda: previous_task.owner is None
          lambda: self.is_sibling_of(previous_task)
      ]
  )
  </code></pre>
  <p>Is overly verbose, even though is still quite readable</p>
  <p>So... is there something I'm missing? Is there any way to be able to do this in a concise way? It seems like overly hard for just lazy condition evaluation</p>
  <p>If these are the only possibilities, I might consider doing an utils library D:</p>
  <p>Edit: Forgot the obvious solution, which I didn't make explicit, where you could just chain <code>and</code>s, but the thing is that this defeats the purpose of <code>all</code>. And that I thought that knowing how to make generators of unrelated values is much useful in the long way than just spamming <code>and</code> which hinders readability and forces you to &quot;hard-code&quot; the conditions in an huge expression</p>
  <pre class="lang-py prettyprint-override"><code>    (previous_task is not None
  and self.task_type == previous_task.task_type
  and self.owner is None
  and previous_task.owner is None
  and self.is_sibling_of(previous_task)
      )
  </code></pre>