How to Resolve Python "TypeError ...
object is not iterable (in Python Functions/Methods)
Python TypeErrors like 'builtin_function_or_method' object is not iterable
, 'method' object is not iterable
, or 'function' object is not iterable
(and their variations mentioning "argument of type...") are common mistakes, especially for beginners. These errors indicate that you are trying to use a function or method itself in a context that requires an iterable (like a for
loop or the in
operator), usually because you forgot to call the function or method using parentheses ()
.
This guide explains why functions/methods aren't directly iterable and provides the simple solution: ensure you call the function/method to get its (presumably iterable) return value.
Understanding the Error: Iterables vs. Callables (Functions/Methods)
- Iterables: Objects that can be looped over, returning their items one by one (e.g., lists, tuples, strings, dictionaries, sets, file objects). They support operations like
for item in iterable:
andelement in iterable
. - Callables (Functions/Methods): Objects that can be called or invoked using parentheses
()
. They represent code to be executed. A function/method object itself is not a collection of items; it's a reference to the code block. Calling it (my_func()
) executes the code and may return an iterable result.
This TypeError
occurs because you provided the function/method object itself (the reference to the code) where Python expected an iterable sequence of items.
The Primary Cause: Missing Parentheses ()
The overwhelming reason for this error is simply forgetting to add the parentheses ()
after a function or method name when you intend to use the value it returns.
Forgetting to Call Built-in Methods (e.g., .keys()
, .values()
, .items()
, .split()
)
my_dict = {'a': 1, 'b': 2}
my_string = "hello world"
try:
# ⛔️ TypeError: 'builtin_function_or_method' object is not iterable
# Trying to loop over the .keys method itself
for k in my_dict.keys: # Missing ()
print(k)
except TypeError as e:
print(f"Error looping over .keys: {e}")
try:
# ⛔️ TypeError: argument of type 'builtin_function_or_method' is not iterable
# Trying to check membership in the .split method itself
if "hello" in my_string.split: # Missing ()
print("Found")
except TypeError as e:
print(f"Error using 'in' with .split: {e}")
Forgetting to Call Custom Class Methods
class DataProvider:
def get_items(self):
return [10, 20, 30]
provider = DataProvider()
try:
# ⛔️ TypeError: 'method' object is not iterable
# Trying to loop over the get_items method itself
for item in provider.get_items: # Missing ()
print(item)
except TypeError as e:
print(f"Error looping over method: {e}")
Forgetting to Call Regular Functions
def generate_letters():
return ('x', 'y', 'z')
try:
# ⛔️ TypeError: 'function' object is not iterable
# Trying to loop over the generate_letters function itself
for letter in generate_letters: # Missing ()
print(letter)
except TypeError as e:
print(f"Error looping over function: {e}")
Contexts Where the Error Occurs
This error appears when you use the function/method reference where an iterable is expected:
In for
Loops (...object is not iterable
)
The for
loop needs something it can request items from sequentially. A function/method object doesn't provide this capability directly.
With in
Operator (argument of type... is not iterable
)
The in
operator checks for membership within a collection. It needs an iterable collection on the right-hand side to check against.
Solution: Add Parentheses ()
to Call the Function/Method
The fix is almost always to add the missing parentheses ()
after the function or method name. This invokes the callable, executes its code, and (presumably) returns the iterable object you intended to work with.
Fixing Built-in Method Calls:
my_dict = {'a': 1, 'b': 2}
my_string = "hello world"
# ✅ Call .keys()
print("Keys:")
for k in my_dict.keys():
print(k)
# ✅ Call .split()
print("Check in split result:")
if "hello" in my_string.split():
print("Found 'hello' in split parts")
Output:
Keys:
a
b
Check in split result:
Found 'hello' in split parts
Fixing Custom Method Call:
class DataProvider:
def get_items(self):
return [10, 20, 30]
provider = DataProvider() # Assuming DataProvider class from before
print("Items from custom method:")
# ✅ Call .get_items()
for item in provider.get_items():
print(item)
Output:
Items from custom method:
10
20
30
Fixing Regular Function Call
def generate_letters():
return ('x', 'y', 'z')
print("Letters from function:")
# ✅ Call generate_letters()
for letter in generate_letters():
print(letter)
Output:
Letters from function:
x
y
z
Secondary Cause: Name Shadowing (Conflicts)
Less commonly, the error might occur if you've accidentally defined a variable or function with the same name as a method, or vice-versa, causing Python to refer to the non-iterable callable when you intended to access an iterable attribute/variable.
# Example: Function name conflicts with list variable
get_data = [100, 200] # This variable holds a list
def get_data(): # This function has the SAME NAME
return [1, 2, 3]
try:
# ⛔️ TypeError: 'function' object is not iterable
# Because the function definition shadowed the list variable,
# 'get_data' now refers to the function, not the list.
for item in get_data:
print(item)
except TypeError as e:
print(f"Name conflict error: {e}")
Solution: Rename Conflicting Variables/Functions/Methods
If name shadowing is the issue, rename either the variable or the function/method so they have unique names within their scope.
data_list = [100, 200] # Renamed variable
def get_data():
return [1, 2, 3]
# ✅ Now iterates over the list correctly
print("Iterating over data_list:")
for item in data_list:
print(item) # Output: 100, 200
# ✅ And the function can still be called separately
print("Calling get_data():")
result_from_func = get_data()
print(result_from_func) # Output: [1, 2, 3]
Output:
Iterating over data_list:
100
200
Calling get_data():
[1, 2, 3]
Debugging the Error
- Check for Parentheses: Look closely at the line indicated in the
TypeError
traceback. Is there a function or method name immediately followed by thefor ... in
or thein
operator without parentheses()
? Add them. - Check
type()
: If adding parentheses doesn't work or seems wrong, print the type of the object you're trying to iterate over right before the loop/in
check:If it outputsprint(f"DEBUG: Type is {type(object_before_iteration)}")
<class 'function'>
,<class 'method'>
, or<class 'builtin_function_or_method'>
, you definitely forgot to call it. - Check for Name Conflicts: If the type seems correct (e.g.,
<class 'list'>
) but you still get the error referring to a function/method, check if you've accidentally redefined a name (shadowing).
Checking if an Object is Iterable (Optional)
You can programmatically check if an object is iterable using try...except
with iter()
, although this isn't usually necessary for fixing this specific error (where the fix is almost always adding ()
).
from collections.abc import Iterable
def my_func(): return [1]
my_list = [1]
def check_iter(obj_name_str, obj):
print(f"Checking '{obj_name_str}' ({type(obj)}):")
try:
iter(obj)
print(" --> Iterable (via iter())")
except TypeError:
print(" --> NOT Iterable (via iter())")
# Python 3.3+ alternative:
# print(f" --> Iterable (via isinstance)? {isinstance(obj, Iterable)}")
check_iter("my_func", my_func) # Not Iterable
check_iter("my_func()", my_func()) # Iterable
check_iter("my_list", my_list) # Iterable
check_iter("my_dict.keys", {}.keys) # Not Iterable
check_iter("my_dict.keys()", {}.keys()) # Iterable
Output:
Checking 'my_func' (<class 'function'>):
--> NOT Iterable (via iter())
Checking 'my_func()' (<class 'list'>):
--> Iterable (via iter())
Checking 'my_list' (<class 'list'>):
--> Iterable (via iter())
Checking 'my_dict.keys' (<class 'builtin_function_or_method'>):
--> NOT Iterable (via iter())
Checking 'my_dict.keys()' (<class 'dict_keys'>):
--> Iterable (via iter())
Conclusion
The family of errors TypeError: '...' object is not iterable
involving function
, method
, or builtin_function_or_method
almost always means you forgot the parentheses ()
needed to call the function or method. Instead of iterating over the result returned by the callable, your code is attempting (and failing) to iterate over the callable object itself.
The fix is simple: Add the parentheses ()
to invoke the function/method (e.g., change my_dict.keys
to my_dict.keys()
, my_func
to my_func()
). Also, be mindful of potential name shadowing issues where variables and functions/methods might share names.