class_docstr: Type of the functions returned by theano.function or
  theano.FunctionMaker.create.
  
  `Function` is the callable object that does computation.  It has the storage
  of inputs and outputs, performs the packing and unpacking of inputs and
  return values. It implements the square-bracket indexing so that you can
  look up the value of a symbolic node.
  
  Functions are copyable via {{{fn.copy()}}} and {{{copy.copy(fn)}}}.
  When a function is copied, this instance is duplicated. Contrast with
  self.maker (instance of `FunctionMaker`) that is shared between copies.
  The meaning of copying a function is that the containers and their current
  values will all be duplicated. This requires that mutable inputs be
  copied, whereas immutable inputs may be shared between copies.
  
  A Function instance is hashable, on the basis of its memory
  address (its id).
  
  A Function instance is only equal to itself.
  
  A Function instance may be serialized using the `pickle` or
  `cPickle` modules.  This will save all default inputs, the graph,
  and WRITEME to the pickle file.
  
  A Function instance have a ``trust_input`` field that default to
  False. When True, we don't do extra check of the input to give
  better error message. In some case, python code will still return
  the good results if you pass a python or numpy scalar instead of a
  numpy tensor.  C code should raise an error if you pass an object
  of the wrong type.
  
  Attributes
  ----------
  finder
  inv_finder
class_docstr_tok: ["Type","of","the","functions","returned","by","theano.function","or","theano.FunctionMaker.create",".","`","Function","`","is","the","callable","object","that","does","computation",".","It","has","the","storage","of","inputs","and","outputs",",","performs","the","packing","and","unpacking","of","inputs","and","return","values",".","It","implements","the","square-bracket","indexing","so","that","you","can","look","up","the","value","of","a","symbolic","node",".","Functions","are","copyable","via","{","{","{","fn.copy","(",")","}","}","}","and","{","{","{","copy.copy","(","fn",")","}","}","}",".","When","a","function","is","copied",",","this","instance","is","duplicated",".","Contrast","with","self.maker","(","instance","of","`","FunctionMaker","`",")","that","is","shared","between","copies",".","The","meaning","of","copying","a","function","is","that","the","containers","and","their","current","values","will","all","be","duplicated",".","This","requires","that","mutable","inputs","be","copied",",","whereas","immutable","inputs","may","be","shared","between","copies",".","A","Function","instance","is","hashable",",","on","the","basis","of","its","memory","address","(","its","id",")",".","A","Function","instance","is","only","equal","to","itself",".","A","Function","instance","may","be","serialized","using","the","`","pickle","`","or","`","cPickle","`","modules",".","This","will","save","all","default","inputs",",","the","graph",",","and","WRITEME","to","the","pickle","file",".","A","Function","instance","have","a","``","trust_input","``","field","that","default","to","False",".","When","True",",","we","do","n't","do","extra","check","of","the","input","to","give","better","error","message",".","In","some","case",",","python","code","will","still","return","the","good","results","if","you","pass","a","python","or","numpy","scalar","instead","of","a","numpy","tensor",".","C","code","should","raise","an","error","if","you","pass","an","object","of","the","wrong","type",".","Attributes","--","--","--","--","--","finder","inv_finder"]
code: def __init__(
      self,
      fn,
      input_storage,
      output_storage,
      indices,
      outputs,
      defaults,
      unpack_single,
      return_none,
      output_keys,
      maker,
      name=None,
  ):
      self.fn = fn
      self.input_storage = input_storage
      self.output_storage = output_storage
      self.indices = indices
      self.outputs = outputs
      self.defaults = defaults
      self.unpack_single = unpack_single
      self.return_none = return_none
      self.maker = maker
      self.profile = None  # reassigned in FunctionMaker.create
      self.trust_input = (
          False  # If True, we don't check the input parameter
      )
      self.name = name
      self.nodes_with_inner_function = []
      self.output_keys = output_keys
  
      # See if we have any mutable / borrow inputs
      # TODO: this only need to be set if there is more then 1 input
      self._check_for_aliased_inputs = False
      for i in maker.inputs:
          # If the input is a shared variable, the memory region is
          # under Theano control and so we don't need to check if it
          # is aliased as we never do that.
          if (
              isinstance(i, In)
              and not i.shared
              and (
                  getattr(i, "borrow", False)
                  or getattr(i, "mutable", False)
              )
          ):
              self._check_for_aliased_inputs = True
              break
  
      # We will be popping stuff off this `containers` object.  It is a copy.
      containers = list(self.input_storage)
      finder = {}
      inv_finder = {}
  
      def distribute(indices, cs, value):
          input.distribute(value, indices, cs)
          for c in cs:
              c.provided += 1
  
      # Store the list of names of named inputs.
      named_inputs = []
      # Count the number of un-named inputs.
      n_unnamed_inputs = 0
  
      # Initialize the storage
      # this loop works by modifying the elements (as variable c) of
      # self.input_storage inplace.
      for i, (
          (input, indices, sinputs),
          (required, refeed, value),
      ) in enumerate(zip(self.indices, defaults)):
          if indices is None:
              # containers is being used as a stack. Here we pop off
              # the next one.
              c = containers[0]
              c.strict = getattr(input, "strict", False)
              c.allow_downcast = getattr(input, "allow_downcast", None)
  
              if value is not None:
                  # Always initialize the storage.
                  if isinstance(value, gof.Container):
                      # There is no point in obtaining the current value
                      # stored in the container, since the container is
                      # shared.
                      # For safety, we make sure 'refeed' is False, since
                      # there is no need to refeed the defaullt value.
                      assert not refeed
                  else:
                      c.value = value
              c.required = required
              c.implicit = input.implicit
              # this is a count of how many times the input has been
              # provided (reinitialized to 0 on __call__)
              c.provided = 0
              finder[i] = c
              finder[input.variable] = c
              if input.name not in finder:
                  finder[input.name] = c
              else:
                  finder[input.name] = DUPLICATE
              if input.name is None:
                  n_unnamed_inputs += 1
              else:
                  named_inputs.append(input.name)
              inv_finder[c] = input
              containers[:1] = []
  
      self.finder = finder
      self.inv_finder = inv_finder
  
      # this class is important in overriding the square-bracket notation:
      #     fn.value[x]
      # self reference is available via the closure on the class
      class ValueAttribute(object):
          def __getitem__(self, item):
              try:
                  s = finder[item]
              except KeyError:
                  raise TypeError(
                      "Unknown input or state: %s" % str(item)
                  )
              if s is DUPLICATE:
                  raise TypeError(
                      "Ambiguous name: %s - please check the "
                      "names of the inputs of your function "
                      "for duplicates." % str(item)
                  )
              if isinstance(s, gof.Container):
                  return s.value
              else:
                  raise NotImplementedError
  
          def __setitem__(self, item, value):
              try:
                  s = finder[item]
              except KeyError:
                  # Print informative error message.
                  msg = get_info_on_inputs(
                      named_inputs, n_unnamed_inputs
                  )
                  raise TypeError(
                      "Unknown input or state: %s. %s"
                      % (str(item), msg)
                  )
              if s is DUPLICATE:
                  raise TypeError(
                      "Ambiguous name: %s - please check the "
                      "names of the inputs of your function "
                      "for duplicates." % str(item)
                  )
              if isinstance(s, gof.Container):
                  s.value = value
                  s.provided += 1
              else:
                  s(value)
  
          def __contains__(self, item):
              return finder.__contains__(item)
  
      # this class is important in overriding the square-bracket notation:
      #     fn.container[x]
      # self reference is available via the closure on the class
      class ContainerAttribute(object):
          def __getitem__(self, item):
              return finder[item]
  
          def __contains__(self, item):
              return finder.__contains__(item)
  
          # You cannot set the container
  
      self._value = ValueAttribute()
      self._container = ContainerAttribute()
  
      # Compute self.n_returned_outputs.
      # This is used only when fn.need_update_inputs is False
      # because we're using one of the VM objects and it is
      # putting updates back into the input containers all by itself.
      assert len(self.maker.expanded_inputs) == len(self.input_storage)
      self.n_returned_outputs = len(self.output_storage)
      for input in self.maker.expanded_inputs:
          if input.update is not None:
              self.n_returned_outputs -= 1
  
      for node in self.maker.fgraph.apply_nodes:
          if node.op in ops_with_inner_function:
              self.nodes_with_inner_function.append(node.op)
  
imports: from __future__ import absolute_import, print_function, division
  import copy
  from six import string_types, iteritems, iterkeys
  from six.moves import xrange
  import six.moves.copyreg
  import six.moves.cPickle
  from itertools import chain
  import time
  import warnings
  import numpy
  import theano
  from theano import config, gof
  from theano.compat import izip
  from theano.gof import graph
  import theano.compile.profiling
  from theano.compile.io import In, SymbolicInput, SymbolicOutput
  from theano.compile.ops import deep_copy_op, view_op
  from theano.gof.graph import is_same_graph
  from theano.gof.op import ops_with_inner_function
  import logging
label_desc: Use image node_id 1 to create a new Function object from inherited base classes: object with example: obj = Function(fn, input_storage, output_storage, indices, outputs, defaults, unpack_single, return_none, output_keys, maker, name)