nodes: 0, module; 1, function_definition; 2, function_name:compose; 3, parameters; 4, block; 5, list_splat_pattern; 6, expression_statement; 7, comment:# slightly optimized for most common cases and hence verbose; 8, if_statement; 9, identifier:funcs; 10, comment:"""Compose `funcs` to a single function.
  
      >>> compose(operator.abs, operator.add)(-2,-3)
      5
      >>> compose()('nada')
      'nada'
      >>> compose(sorted, set, partial(filter, None))(range(3)[::-1]*2)
      [1, 2]
      """; 11, comparison_operator:len(funcs) == 2; 12, block; 13, elif_clause; 14, elif_clause; 15, elif_clause; 16, else_clause; 17, call; 18, integer:2; 19, expression_statement; 20, return_statement; 21, comparison_operator:len(funcs) == 3; 22, block; 23, comparison_operator:len(funcs) == 0; 24, block; 25, comparison_operator:len(funcs) == 1; 26, block; 27, block; 28, identifier:len; 29, argument_list; 30, assignment; 31, lambda; 32, call; 33, integer:3; 34, expression_statement; 35, return_statement; 36, call; 37, integer:0; 38, return_statement; 39, comment:# XXX single kwarg; 40, call; 41, integer:1; 42, return_statement; 43, function_definition; 44, return_statement; 45, identifier:funcs; 46, pattern_list; 47, identifier:funcs; 48, lambda_parameters; 49, call; 50, identifier:len; 51, argument_list; 52, assignment; 53, lambda; 54, identifier:len; 55, argument_list; 56, lambda; 57, identifier:len; 58, argument_list; 59, subscript; 60, function_name:composed; 61, parameters; 62, block; 63, identifier:composed; 64, identifier:f0; 65, identifier:f1; 66, list_splat_pattern; 67, dictionary_splat_pattern; 68, identifier:f0; 69, argument_list; 70, identifier:funcs; 71, pattern_list; 72, identifier:funcs; 73, lambda_parameters; 74, call; 75, identifier:funcs; 76, lambda_parameters; 77, identifier:x; 78, identifier:funcs; 79, identifier:funcs; 80, integer:0; 81, list_splat_pattern; 82, dictionary_splat_pattern; 83, expression_statement; 84, for_statement; 85, return_statement; 86, identifier:a; 87, identifier:kw; 88, call; 89, identifier:f0; 90, identifier:f1; 91, identifier:f2; 92, list_splat_pattern; 93, dictionary_splat_pattern; 94, identifier:f0; 95, argument_list; 96, identifier:x; 97, identifier:args; 98, identifier:kwargs; 99, assignment; 100, identifier:f; 101, subscript; 102, block; 103, identifier:y; 104, identifier:f1; 105, argument_list; 106, identifier:a; 107, identifier:kw; 108, call; 109, identifier:y; 110, call; 111, identifier:funcs; 112, slice; 113, expression_statement; 114, list_splat; 115, dictionary_splat; 116, identifier:f1; 117, argument_list; 118, subscript; 119, argument_list; 120, integer:0; 121, unary_operator; 122, assignment; 123, identifier:a; 124, identifier:kw; 125, call; 126, identifier:funcs; 127, unary_operator; 128, list_splat; 129, dictionary_splat; 130, integer:1; 131, identifier:y; 132, call; 133, identifier:f2; 134, argument_list; 135, integer:1; 136, identifier:args; 137, identifier:kwargs; 138, identifier:f; 139, argument_list; 140, list_splat; 141, dictionary_splat; 142, identifier:y; 143, identifier:a; 144, identifier:kw
code: def compose(*funcs):
      """Compose `funcs` to a single function.
  
      >>> compose(operator.abs, operator.add)(-2,-3)
      5
      >>> compose()('nada')
      'nada'
      >>> compose(sorted, set, partial(filter, None))(range(3)[::-1]*2)
      [1, 2]
      """
      # slightly optimized for most common cases and hence verbose
      if len(funcs) == 2: f0,f1=funcs; return lambda *a,**kw: f0(f1(*a,**kw))
      elif len(funcs) == 3: f0,f1,f2=funcs; return lambda *a,**kw: f0(f1(f2(*a,**kw)))
      elif len(funcs) == 0: return lambda x:x     # XXX single kwarg
      elif len(funcs) == 1: return funcs[0]
      else:
          def composed(*args,**kwargs):
              y = funcs[-1](*args,**kwargs)
              for f in funcs[:0:-1]: y = f(y)
              return y
          return composed