class_docstr: A class that models and constructs operations in a graph.
  
  A `Op` instance has several responsibilities:
  
  * construct `Apply` nodes via :meth:`Op.make_node` method,
  * perform the numeric calculation of the modeled operation via the
    :meth:`Op.perform` method,
  * and (optionally) build the gradient-calculating sub-graphs via the
    :meth:`Op.grad` method.
  
  To see how `Op`, `Type`, `Variable`, and `Apply` fit together see the
  page on :doc:`graph`.
  
  For more details regarding how these methods should behave: see the `Op
  Contract` in the sphinx docs (advanced tutorial on `Op` making).
class_docstr_tok: ["A","class","that","models","and","constructs","operations","in","a","graph",".","A","`","Op","`","instance","has","several","responsibilities",":","*","construct","`","Apply","`","nodes","via",":","meth",":","`","Op.make_node","`","method",",","*","perform","the","numeric","calculation","of","the","modeled","operation","via","the",":","meth",":","`","Op.perform","`","method",",","*","and","(","optionally",")","build","the","gradient-calculating","sub-graphs","via","the",":","meth",":","`","Op.grad","`","method",".","To","see","how","`","Op","`",",","`","Type","`",",","`","Variable","`",",","and","`","Apply","`","fit","together","see","the","page","on",":","doc",":","`","graph","`",".","For","more","details","regarding","how","these","methods","should","behave",":","see","the","`","Op","Contract","`","in","the","sphinx","docs","(","advanced","tutorial","on","`","Op","`","making",")","."]
docstr: Make a Python thunk.
  
  Like :meth:`Op.make_thunk` but only makes Python thunks.
docstr_tok: ["Make","a","Python","thunk",".","Like",":","meth",":","`","Op.make_thunk","`","but","only","makes","Python","thunks","."]
code: def make_py_thunk(
      self,
      node: Apply,
      storage_map: StorageMapType,
      compute_map: ComputeMapType,
      no_recycling: list[Variable],
      debug: bool = False,
  ) -> ThunkType:
      """Make a Python thunk.
  
      Like :meth:`Op.make_thunk` but only makes Python thunks.
  
      """
      node_input_storage = [storage_map[r] for r in node.inputs]
      node_output_storage = [storage_map[r] for r in node.outputs]
  
      if debug and hasattr(self, "debug_perform"):
          p = node.op.debug_perform
      else:
          p = node.op.perform
  
      @is_thunk_type
      def rval(
          p=p, i=node_input_storage, o=node_output_storage, n=node
      ):
          r = p(n, [x[0] for x in i], o)
          for o in node.outputs:
              compute_map[o][0] = True
          return r
  
      rval.inputs = node_input_storage
      rval.outputs = node_output_storage
      setattr(rval, "perform", p)
      rval.lazy = False
      return rval
  
imports: import copy
  import sys
  import warnings
  from abc import ABC, abstractmethod
  from collections.abc import Sequence
  from typing import TYPE_CHECKING, Any, Callable, Optional, Protocol, TypeVar, Union, cast
  import pytensor
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, Variable
  from pytensor.graph.utils import MetaObject, TestValueError, add_tag_trace, get_variable_trace_string
label_desc: Use image node_id 10 for calling the Op obj's underlying member method code with example usage: obj.make_py_thunk(node, storage_map, compute_map, no_recycling, debug) and returns: rval, r