What is the difference in purpose between tf.py_function and tf.function?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
tf.function and tf.py_function both sit at the boundary between Python and TensorFlow execution, but they solve very different problems. tf.function turns TensorFlow-heavy Python code into a TensorFlow graph for tracing and optimization. tf.py_function does the opposite kind of bridge: it lets arbitrary Python code appear inside TensorFlow execution when no pure TensorFlow op is available.
tf.function: trace TensorFlow code into a graph
The purpose of tf.function is to take Python code that uses TensorFlow ops and trace it into a callable graph.
This is useful because TensorFlow can optimize the traced computation, reuse it, and run it in contexts where graph execution matters.
The important point is that tf.function works best when the body is already written in TensorFlow terms. The more Python-side control flow and Python objects dominate the function, the less benefit you get and the more surprising the tracing behavior can become.
tf.py_function: inject raw Python into TensorFlow execution
tf.py_function exists for a different reason. It lets you run a regular Python function as part of TensorFlow execution, usually when you need logic that is not naturally expressed as TensorFlow ops.
This is handy for quick experimentation, legacy Python code, or custom data processing that is difficult to rewrite in TensorFlow. But it comes with tradeoffs: the wrapped code runs in Python, is harder for TensorFlow to optimize, and is not a substitute for a proper TensorFlow op when performance or portability matters.
Their purposes are almost opposite
A simple way to remember the distinction is:
- '
tf.functiontries to move your code deeper into the TensorFlow graph world.' - '
tf.py_functionlets Python leak back into TensorFlow execution when necessary.'
That is why they are not interchangeable. One is about graph tracing and optimization. The other is about compatibility with arbitrary Python logic.
Typical use cases
Use tf.function when:
- Your function is mainly TensorFlow ops
- You want graph execution and tracing benefits
- You are building training, inference, or reusable computation code
Use tf.py_function when:
- You must call ordinary Python code
- You are prototyping quickly
- You need a stopgap for custom logic inside a TensorFlow pipeline
For example, in a dataset pipeline:
This works, but it is usually a fallback, not the ideal long-term implementation.
Why tf.py_function is not a performance tool
Because tf.py_function runs Python code, it keeps execution tied to the Python runtime. That limits graph portability and can become a bottleneck. If the logic can be written using TensorFlow ops, that is usually the better direction.
By contrast, tf.function is specifically about helping TensorFlow capture the computation rather than falling back to arbitrary Python execution.
Common Pitfalls
The biggest mistake is treating tf.py_function as if it were a faster or more graph-friendly version of a normal function. It is usually less optimizable, not more.
Another issue is wrapping Python-heavy code with tf.function and expecting all of it to behave like plain eager Python. Tracing can introduce subtleties around control flow, side effects, and retracing.
Developers also use tf.py_function in data pipelines without realizing that it can reduce portability and complicate performance tuning.
Finally, do not confuse "both accept functions" with "both solve the same problem." The similarity in naming hides a very different purpose.
Summary
- '
tf.functiontraces TensorFlow-based code into a TensorFlow graph.' - '
tf.py_functionwraps arbitrary Python code so it can run during TensorFlow execution.' - '
tf.functionis for graph execution and optimization.' - '
tf.py_functionis for bridging to Python when no convenient TensorFlow op exists.' - If pure TensorFlow ops can express the logic, prefer that over
tf.py_function.

