Both are true

  • functions are objects: do a dir(f) on a function to view its attributes
  • objects can be used as functions: just add __call__(self, ...) method and use the object like a function.

In general things that can be called using a syntax like whatever(x, y, z) are called callables.

What the example is trying to show is that methods are just object attributes that are also callables. Just like you can write obj.x = 5, you can also write obj.f = some_function.

Answer from blue note on Stack Overflow
🌐
Python
docs.python.org › 3 › c-api › code.html
Code Objects — Python 3.14.3 documentation
Prior to Python 3.10, this function would perform basic optimizations to a code object. Changed in version 3.10: This function now does nothing. Code objects contain a bit-field of flags, which can be retrieved as the co_flags Python attribute (for example using PyObject_GetAttrString()), and set using a flags argument to PyUnstable_Code_New() and similar functions.
🌐
Python
docs.python.org › 3 › c-api › function.html
Function Objects — Python 3.14.4 documentation
... Return true if o is a function object (has type PyFunction_Type). The parameter must not be NULL. This function always succeeds. PyObject *PyFunction_New(PyObject *code, PyObject ...
🌐
W3Schools
w3schools.com › python › ref_func_object.asp
Python object() Function
Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Bootcamp Python Certificate Python Training ... The object() function returns an empty object. You cannot add new properties or methods to this object.
Top answer
1 of 2
46

You are looking for the __call__ method. Function objects have that method:

>>> def foo(): pass
... 
>>> foo.__call__
<method-wrapper '__call__' of function object at 0x106aafd70>

Not that the Python interpreter loop actually makes use of that method when encountering a Python function object; optimisations in the implementation jump straight to the contained bytecode in most cases.

But you can use that on your own custom class:

class Callable(object):
    def __init__(self, name):
        self.name = name

    def __call__(self, greeting):
        return '{}, {}!'.format(greeting, self.name)

Demo:

>>> class Callable(object):
...     def __init__(self, name):
...         self.name = name
...     def __call__(self, greeting):
...         return '{}, {}!'.format(greeting, self.name)
... 
>>> Callable('World')('Hello')
'Hello, World!'

Python creates function objects for you when you use a def statement, or you use a lambda expression:

>>> def foo(): pass
... 
>>> foo
<function foo at 0x106aafd70>
>>> lambda: None
<function <lambda> at 0x106d90668>

You can compare this to creating a string or an integer or a list using literal syntax:

listobject = [1, 'two']

The above creates 3 objects without ever calling a type, Python did that all for you based on the syntax used. The same applies to functions.

Creating one yourself can be a little more complex; you need to have a code object and reference to a global namespace, at the very least:

>>> function_type = type(lambda: None)
>>> function_type
<type 'function'>
>>> function_type(foo.__code__, globals(), 'bar')
<function bar at 0x106d906e0>

Here I created a function object by reusing the function type, taking the code object from the foo function; the function type is not a built-in name but the type really does exist and can be obtained by calling type() on an existing function instance.

I also passed in the global namespace of my interpreter, and a name; the latter is an optional argument; the name is otherwise taken from the code object.

2 of 2
8

One simple way to see this is to create a function in the Python interpreter def bar(x): return x + 1 and then use dir(bar) to see the various magic attributes including __class__.

Yes, python functions are full objects.

For another approach, objects are functions if they have a magic __call__() method.

🌐
Readthedocs
python-textbok.readthedocs.io › en › 1.0 › Functions.html
Functions — Object-Oriented Programming in Python 1 documentation
To call the function we use its ... method defined which is executed when the object is called. For example, types such as str, int or list can be used as functions, to create new objects of that type (sometimes by converting an existing object):...
🌐
Medium
medium.com › python-pandemonium › function-as-objects-in-python-d5215e6d1b0d
Functions as Objects in Python. In Python, everything is an object… | by Chaitanya Baweja | Python Pandemonium | Medium
July 19, 2019 - Functions in Python are first-class objects. ... Sending functions as arguments coupled with the ability to store them in lists can be extremely helpful. I know all of this can be hard to digest so let’s take this step by step. For the rest of the tutorial, we will define an ‘apply’ function which will take as input a list, L and a function, f and apply the function to each element of the list. This example has been taken from the Edx Course 6.00.1.x.
Find elsewhere
🌐
Python Like You Mean It
pythonlikeyoumeanit.com › Module2_EssentialsOfPython › Functions.html
Basics of Functions — Python Like You Mean It
The following is the general syntax for defining a Python function: def <function name>(<function signature>): """ documentation string """ <encapsulated code> return <object> <function name> can be any valid variable name, and must be followed by parentheses and then a colon. <function signature> specifies the input arguments to the function, and may be left blank if the function does not accept any arguments (the parentheses must still be included, but will not encapsulate anything).
🌐
Python documentation
docs.python.org › 3 › library › functions.html
Built-in Functions — Python 3.14.4 documentation
February 27, 2026 - Changed in version 3.6: Grouping digits with underscores as in code literals is allowed. Changed in version 3.8: Falls back to __index__() if __complex__() and __float__() are not defined. Deprecated since version 3.14: Passing a complex number as the real or imag argument is now deprecated; it should only be passed as a single positional argument. ... This is a relative of setattr(). The arguments are an object and a string. The string must be the name of one of the object’s attributes. The function deletes the named attribute, provided the object allows it.
🌐
Stack Overflow
stackoverflow.com › questions › 78716221 › is-there-any-way-to-construct-a-code-object-from-a-code-string-and-assign-it-to
Is there any way to construct a code object from a code string and assign it to an existing function using Python? - Stack Overflow
You can only replace whole __code__, and that would be marginally easier: just write a new function, take its __code__ and assign. def your_func(...): ... and func1.__code__ = your_func.__code__. ... What advantage is there in manipulating the low-level __code__ object instead of just monkeypatching (which you said you do not want to do)?
🌐
Duke University
people.duke.edu › ~ccc14 › sta-663 › FunctionsSolutions.html
Functions are first class objects — Computational Statistics in Python 0.1 documentation
In Python, functions behave like any other object, such as an int or a list. That means that you can use functions as arguments to other functions, store functions as dictionary values, or return a function from another function.
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-functions
Python Functions - GeeksforGeeks
Immutable objects: The original value remains unchanged. ... def myFun(x): x[0] = 20 lst = [10, 11, 12, 13] myFun(lst) print(lst) def myFun2(x): x = 20 a = 10 myFun2(a) print(a) ... Note: Python always passes objects by reference.
Published   3 weeks ago
🌐
Aknin
tech.blog.aknin.name › 2010 › 07 › 03 › pythons-innards-code-objects
Python’s Innards: Code Objects – NIL: .to write(1) ~ help:about
If you happen to really care how this is encoded you can either look at ./Python/compile.c or ./Lib/dis.py: findlinestarts. ... An integer encoding a number of flags regarding the way this code object was created (which says something about how it should be evaluated). The list of possible flags is listed in ./Include/code.h, as a small example I can give CO_NESTED, which marks a code object which was compiled from a lexically nested function.
Top answer
1 of 3
3

You already extracted the code objects, now all you have to do is to create the functions objects using types.FuncitonType. It accepts:

  1. Code object
  2. Reference to the global module
  3. Name
from types import FunctionType

code_string = """\
def f1(p1, p2, p3):
    print("a{}, b{}, c{}".format(p1, p2, p3))
def f2():
    print("text")
"""

code = compile(code_string, "<string>", "exec")

f1_code_object = code.co_consts[0]
f2_code_object = code.co_consts[1]

f1 = FunctionType(f1_code_object, globals(), "f1")
f2 = FunctionType(f2_code_object, globals(), "f2")
print(f1)
print(f2)
f1(10, 20, 30)
f2()

output:

<function f1 at 0x1042a2980>
<function f2 at 0x1042a2a20>
a10, b20, c30
text
2 of 3
1

All compile() does is translate the Python source code (think contents of *.py files) into a compiled version (think *.pyc files). The source code must be syntactically correct, but need not be valid. In the case of your code_string, this means it has compiled the two def <name>: <body> statements into a binary form, but it has not executed those def statements to actually create the functions.

You need to execute the compiled code object in order to actually execute the def statement that creating the functions.

However, as norok2 mentions, simply executing code in arbitrary strings is a security risk. It can be done somewhat safer by controlling the environment the code is executed in. We can create an environment where the only function that exists is the print function:

code_string = """\
def f1(p1, p2, p3):
    print("a{}, b{}, c{}".format(p1, p2, p3))
def f2():
    print("text")
"""

code = compile(code_string, '<string>', 'exec')

builtins = {
    'print': print,
    }

code_globals = {'__builtins__': builtins}
exec(code, code_globals)

f1 = code_globals['f1']
f_two = code_globals['f2']

f1(1, 2, 3)
f_two()

Now it is much more difficult for the code to break out of the sandbox. For example, if you add import sys inside the code_string, you'll get an NameError: name '__import__' is not defined., and so on.

By careful construction of the available builtins, you can allow as much functionality as needed.

Of course, since we are no longer using the caller's global context to create the definitions, you need to extract the created functions out of the code_globals dictionary, as demonstrated above.


Why compile?

You generally use compile() when you want to execute the resulting code multiple times. That's not the case here. You will likely be executing the code exactly once to create the f1 and f2 functions. (Once created, they can be called many times, but they only need to be created once.) Therefore, we should use exec() instead of compile(), so we don't get (and accidentally keep) a reference to the intermediate code object:

code_string = """\
def f1(p1, p2, p3):
    print("a{}, b{}, c{}".format(p1, p2, p3))
def f2():
    print("text")
"""

builtins = {
    'print': print,
    }

code_globals = {'__builtins__': builtins}
exec(code_string, code_globals)

f1 = code_globals['f1']
f_two = code_globals['f2']

f1(1, 2, 3)
f_two()

Why code.co_consts is fragile

S.B shows how you can directly create functions from code.co_consts[...], and indirectly demonstrates how fragile this is.

Consider the OP's code:

f2 = code.co_consts[2]

compared with S.B's:

f2_code_object = code.co_consts[1]

Apparently, something changed (Python version? An edit to the code_string?) and f2 moved from index 2 to index 1. There is no obvious mapping from the indices in co_consts to the expected function names.

To drive this home, consider this more complex example, which highlights the differences between compiling the Python script and executing it:

from types import FunctionType

code_string = """\
if True == False:
    print("Defining f1...")
    def f1(p1, p2, p3):
        print("a{}, b{}, c{}".format(p1, p2, p3))
else:
    print("Defining alternate f1")
    def f1(p1, p2, p3):
        print("c{}, b{}, a{}".format(p3, p2, p1))
"""

builtins = {
    'print': print,
    }
code_globals = {'__builtins__': builtins}

print("Using compile() and code.co_consts")
code = compile(code_string, '<string>', 'exec')

for idx, item in enumerate(code.co_consts):
    print(f"  .co_consts[{idx}] = {item!r}")

f1 = FunctionType(code.co_consts[3], code_globals) # How do we know it is 3???
f1(1, 2, 3)

print()
print("Using exec():")
code_globals = {'__builtins__': builtins}
exec(code_string, code_globals)

f1 = code_globals['f1']
f1(1, 2, 3)

Now code_string will conditionally define the function f1 based on the execution of the code.

Output:

Using compile() and code.co_consts
  .co_consts[0] = True
  .co_consts[1] = False
  .co_consts[2] = 'Defining f1...'
  .co_consts[3] = <code object f1 at 0x000001A3B567FA30, file "<string>", line 3>
  .co_consts[4] = 'Defining alternate f1'
  .co_consts[5] = <code object f1 at 0x000001A3B56C8330, file "<string>", line 7>
  .co_consts[6] = None
a1, b2, c3

Using exec():
Defining alternate f1
c3, b2, a1

Note that:

  • compile()
    • created two different code object f1 entities,
    • does not execute either print() statement.
  • exec()
    • actually evaluates the condition in the if statement,
    • executes the print() statement in one code path,
    • defines the function "f1" from that code path only.
🌐
Rip Tutorial
riptutorial.com › exploring the code object of a function
Python Language Tutorial => Exploring the code object of a function
The __code__object contains the raw bytecode (co_code) of the function as well as other information such as constants and variable names. def fib(n): if n <= 2: return 1 return fib(n-1) + fib(n-2) dir(fib.__code__) def fib(n): if n <= 2: return ...
🌐
Python
docs.python.org › dev › c-api › function.html
Function Objects — Python 3.14.0a7 documentation
... Return true if o is a function object (has type PyFunction_Type). The parameter must not be NULL. This function always succeeds. PyObject *PyFunction_New(PyObject *code, PyObject ...
🌐
The Python Coding Stack
thepythoncodingstack.com › p › python-functions-first-class-objects
"I'm One of You!" Said the Function to the Other Objects
April 7, 2024 - You even create a new name for the same function. The function names create_menu and order_food refer to the same function—the same object. Every object in Python can be used in places where Python is expecting a true-or-false value.
🌐
Python.org
discuss.python.org › python help
Executing code objects from `fn.__code__` vs code objects from compile - Python Help - Discussions on Python.org
April 30, 2024 - In the below code, def foo(): a = 5 b = 7 print ('a + b =', a + b) exec(foo.__code__) it correctly prints a + b = 12 but the following does not print anything. import inspect def foo(): a = 5 b =…