code: def _py_func_with_gradient(func, inp, Tout, stateful=True, name=None,
                             grad_func=None):
    
    # Generate random name in order to avoid conflicts with inbuilt names
    rnd_name = 'PyFuncGrad-' + '%0x' % getrandbits(30 * 4)
  
    # Register Tensorflow Gradient
    tf.RegisterGradient(rnd_name)(grad_func)
  
    # Get current graph
    g = tf.get_default_graph()
  
    # Add gradient override map
    with g.gradient_override_map({"PyFunc": rnd_name,
                                  "PyFuncStateless": rnd_name}):
      return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
docs: PyFunc defined as given by Tensorflow
    :param func: Custom Function
    :param inp: Function Inputs
    :param Tout: Ouput Type of out Custom Function
    :param stateful: Calculate Gradients when stateful is True
    :param name: Name of the PyFunction
    :param grad: Custom Gradient Function
    :return: