title: Python: How to generate Full Factorial Combinations?
body: <p>How can I use python to generate a full factorial of combinations?  Is there a fancy <code>itertools</code> function that generates a full factorial? </p>
  
  <p>I'm drawing a blank and can't think of another way to describe this other than "full factorial of combinations", so my search efforts have turned up with nothing relevant. What's the right terminology here? Search has turned up with combinations of certain lengths, but that's not what I'm after. The length is fixed by the number of factors. </p>
  
  <p><em>Bonus: how to exclude certain combinations? how to do for arbitrary number of factors with arbitrary number of levels with the condition that the "levels" are not necessarily strings but any python object?</em></p>
  
  <p>Let's say I have 5 factors, each with two or more levels.  In this case I have 3 two-level factors and 2 three-level factors.  The full factorial of combinations would have (2^3)*(3^2) = 8*9 = 72 combinations.  Keep in mind that <code>"L1"</code> in <code>X1</code> is different than <code>"L1"</code> in <code>X2</code>.</p>
  
  <p><strong>Input:</strong></p>
  
  <pre class="lang-python prettyprint-override"><code>X1 = ["L1", "L2"]
  X2 = ["L1", "L2", "L3"]
  X3 = ["L1", "L2"]
  X4 = ["L1", "L2"]
  X5 = ["L1", "L2", "L3"]
  
  full_factorial_combinations = itertools.fancyfunction(X1, X2, X3, X4, X5)
  full_factorial_combinations #optionally produces a generator instead of list of tuples shown here
  </code></pre>
  
  <p><strong>Output:</strong></p>
  
  <pre class="lang-python prettyprint-override"><code>[("L1", "L1", "L1", "L1", "L1"),
  ("L1", "L1", "L1", "L1", "L2"),
  ("L1", "L1", "L1", "L1", "L3"),
  ("L1", "L1", "L1", "L2", "L1"),
  ("L1", "L1", "L1", "L2", "L2"),
  ("L1", "L1", "L1", "L2", "L3"),
  ("L1", "L1", "L2", "L1", "L1"),
  ("L1", "L1", "L2", "L1", "L2"),
  ("L1", "L1", "L2", "L1", "L3"),
  ("L1", "L1", "L2", "L2", "L1"),
  ("L1", "L1", "L2", "L2", "L2"),
  ("L1", "L1", "L2", "L2", "L3"),
  ("L1", "L2", "L1", "L1", "L1"),
  ("L1", "L2", "L1", "L1", "L2"),
  ("L1", "L2", "L1", "L1", "L3"),
  ("L1", "L2", "L1", "L2", "L1"),
  ("L1", "L2", "L1", "L2", "L2"),
  ("L1", "L2", "L1", "L2", "L3"),
  ("L1", "L2", "L2", "L1", "L1"),
  ("L1", "L2", "L2", "L1", "L2"),
  ("L1", "L2", "L2", "L1", "L3"),
  ("L1", "L2", "L2", "L2", "L1"),
  ("L1", "L2", "L2", "L2", "L2"),
  ("L1", "L2", "L2", "L2", "L3"),
  ("L1", "L3", "L1", "L1", "L1"),
  ("L1", "L3", "L1", "L1", "L2"),
  ("L1", "L3", "L1", "L1", "L3"),
  ("L1", "L3", "L1", "L2", "L1"),
  ("L1", "L3", "L1", "L2", "L2"),
  ("L1", "L3", "L1", "L2", "L3"),
  ("L1", "L3", "L2", "L1", "L1"),
  ("L1", "L3", "L2", "L1", "L2"),
  ("L1", "L3", "L2", "L1", "L3"),
  ("L1", "L3", "L2", "L2", "L1"),
  ("L1", "L3", "L2", "L2", "L2"),
  ("L1", "L3", "L2", "L2", "L3"),
  ("L2", "L1", "L1", "L1", "L1"),
  ("L2", "L1", "L1", "L1", "L2"),
  ("L2", "L1", "L1", "L1", "L3"),
  ("L2", "L1", "L1", "L2", "L1"),
  ("L2", "L1", "L1", "L2", "L2"),
  ("L2", "L1", "L1", "L2", "L3"),
  ("L2", "L1", "L2", "L1", "L1"),
  ("L2", "L1", "L2", "L1", "L2"),
  ("L2", "L1", "L2", "L1", "L3"),
  ("L2", "L1", "L2", "L2", "L1"),
  ("L2", "L1", "L2", "L2", "L2"),
  ("L2", "L1", "L2", "L2", "L3"),
  ("L2", "L2", "L1", "L1", "L1"),
  ("L2", "L2", "L1", "L1", "L2"),
  ("L2", "L2", "L1", "L1", "L3"),
  ("L2", "L2", "L1", "L2", "L1"),
  ("L2", "L2", "L1", "L2", "L2"),
  ("L2", "L2", "L1", "L2", "L3"),
  ("L2", "L2", "L2", "L1", "L1"),
  ("L2", "L2", "L2", "L1", "L2"),
  ("L2", "L2", "L2", "L1", "L3"),
  ("L2", "L2", "L2", "L2", "L1"),
  ("L2", "L2", "L2", "L2", "L2"),
  ("L2", "L2", "L2", "L2", "L3"),
  ("L2", "L3", "L1", "L1", "L1"),
  ("L2", "L3", "L1", "L1", "L2"),
  ("L2", "L3", "L1", "L1", "L3"),
  ("L2", "L3", "L1", "L2", "L1"),
  ("L2", "L3", "L1", "L2", "L2"),
  ("L2", "L3", "L1", "L2", "L3"),
  ("L2", "L3", "L2", "L1", "L1"),
  ("L2", "L3", "L2", "L1", "L2"),
  ("L2", "L3", "L2", "L1", "L3"),
  ("L2", "L3", "L2", "L2", "L1"),
  ("L2", "L3", "L2", "L2", "L2"),
  ("L2", "L3", "L2", "L2", "L3")]
  </code></pre>