Welcome to the next pikoTutorial!
Changing function behavior by modifying its implementation manually is obvious, but can we somehow mess around with the implementations of the functions at runtime of the application? Let’s organize this process in 3 steps:
- obtaining function’s source code at runtime
- converting string with source code to a callable object
- modify function’s source code before calling it
Obtaining function’s source code at runtime
Let’s first learn how to obtain a source code of the function:
# Import inspect module
import inspect
# Define some callback function
def function():
print('Do something')
source_code = inspect.getsource(function)
print(source_code)Output:
def callback():
print('Do something')Converting string with source code to a callable object
Now let’s see how to convert some arbitrary Python code provided in a string to a callable Python object:
# Source code that we want to execute
source_code = 'print("Hello from the inside of the string!")'
# Wrap the source code into a function definition, so that it can be accessed by name
function_name = 'print_hello'
function_definition = f'def {function_name}():\n {source_code}'
namespace = {}
# Execute code with a function definition within the given namespace, so that the function definition is created
exec(function_definition, namespace)
# Retrieve function from the namespace and save to a callable variable
print_hello = namespace[function_name]
# Call the function
print_hello()Output:
Hello from the inside of the string!Modifying function’s source code before calling it
Now let’s implement a function which takes as an input a function pointer and returns a callable object with the modified source code:
import inspect
def get_hacked_function(function):
# Get the source code of the given function
original_function_source_code = inspect.getsource(function)
# Append a new line to the function source code
modified_function_source_code = f'{original_function_source_code} print("You didn\'t expect me here!")'
# Call the function within the namespace
namespace = {}
exec(modified_function_source_code, namespace)
# Parse function name by taking everything what's between "def " and "(" at the first line
function_name = original_function_source_code.split('(')[0].split()[1]
# Retrieve modified function
modified_function = namespace[function_name]
# Return modified function
return modified_function
AI is powerful. Snippets are instant.
Stop prompting for the same patterns repeatedly. Get almost 100 free VS Code snippets for C++, Python, CMake and Bazel from piko::snippets GitHub repository.
It’s time to test it!
# This is the function passed as an input
def original_function():
print("Hello")
# Call our hacking function
hacked_function = get_hacked_function(original_function)
# Call the modified function
hacked_function()
Output:
Hello
You didn't expect me here!Note for beginners: please keep in mind that such experiments are done mainly for educational purposes. Using the
exec()function can introduce serious security issues, so it is not recommended to use it in a production environment. If you need to modify the behavior of a function whose source code you don’t have access to, consider using function decorators instead. Always be cautious and ensure you fully understand the security implications before usingexec().
Read also:
- Storing your ATTiny program in…EEPROM?
- Bug of the week #12
- Sharing variable between bash scripts
- A 40-line LLM-based bash command executor in Python
- GTest and short-circuit evaluation in C++
- AI is powerful. Snippets are instant.
- From AUTOSAR to S-Core: the first C++ pub/sub implementation
- How to write Arduino Uno code with Python?
- Combining Bazel with Docker
- Running commands with timeout on Linux
- Running Python unit tests with CMake
- Thirdparty dependencies with FetchContent
- Bug of the week #11
- Combining CMake with Docker
- How to search the internet from Linux terminal?
- Folding expressions in C++
- How to derive from an enum in Python?
- Bug of the week #10
- Trying ROS2: client/server within a single container
- Make C++ a better place #4: Go as an alternative
- How to convert hex to dec in Linux terminal?
- Setting up a Python project with CMake
- Separating builds for different configs with Bazel
- Trying ROS2: pub/sub within a single container
- Bug of the week #9
- UDP multicasting with Python
- Destruction order vs thread safety in C++
- Let’s review some code: C++ #2
- Make C++ a better place #3: D as an alternative
- Registering callback using std::function in C++
- Bug of the week #8
- TCP client/server with Python
- Simple menus in Bash scripts with select
- Calling member function on a nullptr in C++
- Bug of the week #7
- Python lru_cache explained
- How to dockerize a Python application?
- Make C++ a better place #2: CppFront as an alternative
- Parameters combinations in GoogleTest
- Data transfer with curl
- Python reduce explained
- Bug of the week #6
- Custom literals in C++
- Linux and hash command
- 5 Python good practices which make life easier
- Let’s review some code: Python #1
- Make C++ a better place #1: What does better mean
- Enums vs enum class in C++
- Bug of the week #5
- UDP client/server with Python
- Hard links in Linux
- Functions calling order in unit tests in C++
- Bug of the week #4
- Yield in Python – state machines, coroutines and more
- Copy files from another branch with Git
- Make C++ a better place #0: Introduction
- 5 misconceptions about std::move in C++
- How to use xargs on Linux?
- How to test method call order with unittest in Python?
- Bug of the week #3









