<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def template(key, books=None, optional=False):
 """Starts a Pretty Tensor graph template. ## Template Mode Templates allow you to define a graph with some unknown values. The most common use case is to leave the input undefined and then define a graph normally. The variables are only defined once the first time the graph is constructed. For example: template = (pretty_tensor.template('input') .fully_connected(200, name='l1') .fully_connected(200, name='l2')) train_output = template.construct(input=train_data) # All parameters are reused when the same template object is called again. test_output = template.construct(input=test_data) Any argument to a pretty tensor method can be substituted by using an `UnboundVariable`. This allows you to parameterize a graph in arbitrary ways. The most cannonical usage would be to substitute a phase variable. with pretty_tensor.defaults_scope(phase=UnboundVariable('train')):
 # dropout uses train to optionaly disable itself. template = (pretty_tensor.template('input') .fully_connected(200, name='l1') .fully_connected(200, name='l2') .dropout(.8)) train_output = template.construct(input=train_data, train=True) test_output = template.construct(input=test_data, train=False) You should use caution because if a template is called with incompatible values (e.g. train and test using different widths), then it will break. This is because we guarantee variable reuse across instantiations. template = (pretty_tensor.template('input') .fully_connected(200, name='l1') .fully_connected( pretty_tensor.UnboundVariable('width'), name='l2')) train_output = template.construct(input=train_data, width=200) # The following line will die because the shared parameter is the wrong # size. test_output = template.construct(input=test_data, width=100) A Layer in the resulting graph can be realized by calling `bind(key=value)` and then `construct`. Args: key: A key for this template, used for assigning the correct substitution. books: The bookkeeper. optional: If this template is an optional value. Returns: A template that can be constructed or attached to other layers and that guarantees parameter reuse when constructed/attached multiple times. """

  if books is None:
    books = bookkeeper.for_default_graph()

  def set_input_from_unbound_var(data):
    """Sets the input from the given unbound_var."""
    if data is not None:
      return wrap(data, books)
    else:
      return None

  if optional:
    data = UnboundVariable(key=key, default=None)
  else:
    data = UnboundVariable(key=key)
  return _DeferredLayer(books, set_input_from_unbound_var, [data], {})