Definition
A perfectly reasonable line, a script launched, and Python stops dead: the method used every day supposedly does not exist. The scene puzzles as long as the dot is read as a separator. It is really a request made to the object: hand over whatever it keeps under that name.
AttributeError is Python's answer when the request fails. The interpreter looks for the name written after the dot, finds it neither on the object nor on its class, and stops rather than invent a value. Its message always names the real type of the object, then the name requested.
message = "believemy"
# append does exist in Python, but on lists, not on strings
message.append("!")
# AttributeError: 'str' object has no attribute 'append'Python does not say the name is misspelled, it says it does not exist on that type. The nuance moves the investigation: the question is no longer how the method is spelled, but what the variable holds.
It also separates two neighbouring errors. A typo on a bare variable gives a NameError, no name of that kind existing in scope. The same typo after a dot does give an AttributeError: the name may exist elsewhere, just not here.
Reading the message the right way
The first instinct is to hunt for the correct method name. It is almost always the wrong one: nine times out of ten the method is right, and the object is not what you think.
The message splits into two halves, each asking a different question. Here is which one to ask first.
| What the message says | The question it should raise |
|---|---|
'str' object | Why is this object of that type? |
has no attribute 'append' | Does that name exist on that type? |
| The traceback line | Where was the object built? |
Start with the first row. An expected list that arrived as a string, a dictionary where an object was planned, a number instead of a text: none of these cases is solved by changing the method.
What remains is finding where the object picked up that type, and on that point the traceback misleads: it points at the line that failed, not at the one that built the faulty object. Walk back to where the variable receives its value.
The NoneType case, by far the most frequent
One variant comes up often enough to deserve its own treatment: 'NoneType' object has no attribute. It reports an absence rather than an exotic type: the variable holds None, so an operation upstream handed nothing back.
line = "first;last;age"
# split does return a list, but sort orders it in place and returns nothing
fields = line.split(";").sort()
fields.index("last")
# AttributeError: 'NoneType' object has no attribute 'index'fields does not pick up the sorted list but the absence of a value, and it is the next line that fails. The error shows up one step after its cause, hence the time lost rereading the wrong statement.
That silence is deliberate: a method changing an object in place returns None to avoid suggesting a copy was produced. Chaining a call behind such a method is therefore always a mistake.
The cause almost always sits in one of three places. The most common is the one in the example: a method that modifies in place, such as sort, append or update, with a call hooked behind it.
Next comes the home-made function whose path forgets the return: the return is written inside a condition, and the caller receives an absence of value without being warned. Last comes the fruitless lookup, many functions reporting failure with None.
Fixing rather than hiding
On an object you write, the type is right but the attribute was never created: either it is defined somewhere other than __init__, in a method not called yet, or a singular name has been confused with its plural. Here the message names the class, so it names the file to open.
class Basket:
def __init__(self):
self.items = [] # the attribute carries a plural
basket = Basket()
basket.item
# AttributeError: 'Basket' object has no attribute 'item'When the attribute really is optional, two built-in functions avoid the crash without hiding anything. hasattr(obj, "name") answers true or false and is there to branch the code. getattr(obj, "name", default) hands back a fallback value, which spares the condition. A try block works too, provided the case is handled inside it.
An except AttributeError followed by a pass fixes nothing: the program carries on with missing data, and the error resurfaces further down in an unrecognisable shape.
Frequently asked questions
What is the difference with a TypeError?
A TypeError reports an impossible operation between incompatible types, an addition between a text and a number for instance. AttributeError is only about the name looked up after the dot. Both often trace back to the same cause: an object that is not of the expected type.
Should hasattr or a try block be preferred?
hasattr reads better when the presence of the attribute is a genuine business question, an optional setting for example. The try block becomes preferable as soon as the access belongs to the normal path, since it avoids looking the attribute up twice.
Why does the error mention a module?
Because a module is an object like any other. The message module has no attribute shows up after a successful but misaimed import, or when a personal file carries the name of a well-known library and takes its place. Otherwise, it is a ModuleNotFoundError.