Every object in Python carries data around with it. Attributes are how that data gets stored and named — and once you understand them, the way Python classes and objects work starts to make a lot more sense.
When Python creates an object, it needs somewhere to store that object's data. A Dog object needs to remember its name and breed. A BankAccount object needs to track its balance. That stored data lives in attributes. This tutorial walks through what attributes are, how Python looks them up, and what tools are available for working with them directly.
What Is an Attribute?
An attribute is a named value that belongs to an object. You access it using a dot between the object and the attribute name. If dog is an object and it has a name attribute, you write dog.name to read it.
That dot is doing real work. Python looks up the name on the right side of the dot by searching the object's internal data store. For most objects, that store is a dictionary called __dict__, which holds every attribute as a key-value pair.
class Dog:
def __init__(self, name, breed):
self.name = name # instance attribute
self.breed = breed # instance attribute
rex = Dog("Rex", "German Shepherd")
print(rex.name) # Rex
print(rex.breed) # German Shepherd
print(rex.__dict__) # {'name': 'Rex', 'breed': 'German Shepherd'}
The two assignments inside __init__ — self.name = name and self.breed = breed — are what create the attributes. The keyword self refers to the object being created, so you are saying "store this value on this particular object."
__dict__ shows you the full picture of an instance's attributes at any moment. Printing it during debugging is a fast way to confirm which values are actually stored on an object.
Build the correct statement to set a name instance attribute inside __init__:
self.attribute_name = value. The self keyword refers to the current object, the dot connects the attribute name to it, and the right side holds the value being stored. cls is used with class methods, not instance attribute assignment. __init__ is the method name itself, not a token that appears inside it.
Instance Attributes vs. Class Attributes
Not all attributes belong to individual objects. Some attributes are defined at the class level and shared across every instance. This distinction matters because it changes where the value lives and how Python finds it.
An instance attribute is defined inside a method — usually __init__ — using self. It is stored in the object's own __dict__. Each object gets its own copy, so changing one object's attribute does not affect any other object.
A class attribute is defined directly in the class body, outside any method. It is stored on the class itself, not on individual instances. Every instance can read it, but there is only one copy of the value unless an instance overrides it.
class Dog:
species = "Canis lupus familiaris" # class attribute
def __init__(self, name):
self.name = name # instance attribute
rex = Dog("Rex")
fido = Dog("Fido")
print(rex.species) # Canis lupus familiaris
print(fido.species) # Canis lupus familiaris (same value, shared)
print(rex.name) # Rex
print(fido.name) # Fido (each instance has its own)
When Python evaluates rex.species, it first checks rex.__dict__. The attribute is not there, so Python moves up to the class and finds it there. This lookup chain — instance first, then class, then parent classes — is how attribute resolution works in Python.
Use class attributes for values that are truly shared and constant across all instances, like a species name or a version number. If the value will differ from object to object, it belongs in __init__ as an instance attribute.
- Where defined
- Inside a method, using
self.name = value - Where stored
- On the individual object's
__dict__ - Scope
- Unique to each instance; changes do not affect other objects
- Where defined
- In the class body, outside any method
- Where stored
- On the class object itself, not on instances
- Scope
- Shared by all instances unless shadowed by an instance attribute of the same name
- What happens
- Assigning
instance.attr = valuecreates a new entry in the instance's__dict__, which Python finds first - Effect on the class
- The class attribute is unchanged; only that specific instance now sees a different value
- Effect on other instances
- Unaffected — they still read the original class attribute
This class is meant to store a dog's name and breed. One line has a bug that will prevent the attributes from being saved correctly. Click the line you think is wrong, then hit check.
breed = self.breed to self.breed = breed. The assignment is backwards. self.breed = breed stores the value from the parameter onto the object. As written, the code tries to read a self.breed attribute that does not exist yet and assign it to a local variable, which raises an AttributeError at runtime.
The Built-In Attribute Functions
Python provides four built-in functions for working with attributes by name as a string. These become useful when the attribute name is not known until the program is running — for example, when reading configuration files or processing data dynamically.
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
rex = Dog("Rex", "German Shepherd")
# hasattr — check if an attribute exists
print(hasattr(rex, "name")) # True
print(hasattr(rex, "color")) # False
# getattr — read an attribute by name string
print(getattr(rex, "name")) # Rex
print(getattr(rex, "color", "unknown")) # unknown (default returned)
# setattr — assign an attribute by name string
setattr(rex, "color", "black")
print(rex.color) # black
# delattr — remove an attribute
delattr(rex, "color")
print(hasattr(rex, "color")) # False
"Objects are Python's abstraction for data." — Python Language Reference
The optional third argument to getattr is especially practical. Without it, reading a missing attribute raises an AttributeError. Providing a default means your code can continue gracefully when an attribute may or may not be present, without needing a separate hasattr check first.
Calling delattr on an attribute that does not exist raises an AttributeError, just like accessing a missing attribute directly. Always check with hasattr first, or catch the exception, if deletion is conditional.
How to Define and Use Attributes in Python
The following steps walk through the complete process of setting up a class with both instance and class attributes, creating objects, and using the built-in attribute functions.
-
Define a class with an
__init__methodCreate a class using the
classkeyword and define an__init__method. Inside__init__, assign values usingself.attribute_name = value. Each assignment creates an instance attribute that will exist on every object created from this class. -
Create an object and access its attributes
Instantiate the class by calling it with the required arguments — for example,
Dog("Rex", "Shepherd"). The resulting object now has all the instance attributes you defined. Read them using dot notation:rex.name. Assign new values the same way:rex.name = "Max". -
Add a class attribute shared by all instances
Define a variable in the class body, above any method. This becomes a class attribute. Every instance can read it through the normal attribute lookup chain. If you need to change it for all instances at once, assign to
ClassName.attribute. Assigning toinstance.attributecreates an instance attribute that shadows the class one only for that object. -
Use
getattr,setattr,hasattr, anddelattrWhen the attribute name is stored in a variable rather than written directly in code, use the built-in functions. Check existence with
hasattr(obj, name), read withgetattr(obj, name, default), write withsetattr(obj, name, value), and remove withdelattr(obj, name). These functions accept the attribute name as a plain string, making them useful for dynamic or data-driven code.
Python Learning Summary Points
- An attribute is a named value stored on an object, accessed using dot notation. Python stores most instance attributes in a dictionary called
__dict__that you can inspect at any time. - Instance attributes are defined inside methods with
selfand belong to individual objects. Class attributes are defined in the class body and are shared by all instances, though any instance can shadow them with its own value of the same name. - The four built-in attribute functions —
hasattr,getattr,setattr, anddelattr— let you work with attributes using string names, which is essential for dynamic or configurable code.
Attributes are central to how Python's object model works. Everything you do with classes — storing state, building methods, inheriting behavior — depends on this foundation. Spend time reading __dict__ output while experimenting; seeing the data directly reinforces the concepts faster than diagrams alone.
Frequently Asked Questions
An attribute in Python is a named value attached to an object. Attributes store data associated with that object and are accessed using dot notation, for example object.attribute_name.
An instance attribute belongs to a specific object and is usually defined inside __init__ using self. A class attribute is defined directly in the class body and is shared by all instances of that class.
You access an attribute using dot notation: object.attribute_name. You can also use the built-in getattr(object, 'attribute_name') function, which lets you retrieve attributes by name as a string.
self refers to the current instance of the class. When you write self.name = value inside __init__, you are creating an instance attribute that belongs specifically to that object.
__dict__ is a built-in attribute that returns a dictionary of all instance attributes for a given object. It shows each attribute name as a key and its current value as the corresponding value.
Use the built-in hasattr(object, 'attribute_name') function. It returns True if the attribute exists on the object and False if it does not.
Yes. You can assign a new attribute to an object at any time using dot notation (object.new_attr = value) or using setattr(object, 'new_attr', value). The attribute is added to that instance's __dict__.
Use the built-in delattr(object, 'attribute_name') or the del statement: del object.attribute_name. After deletion, attempting to access that attribute will raise an AttributeError.
The instance attribute shadows the class attribute for that specific object. Python checks the instance's __dict__ first, so the instance value takes precedence. Other instances that do not override the attribute still see the class-level value.
getattr(object, name) retrieves the value of a named attribute from an object. It accepts an optional third argument as a default value, which is returned instead of raising AttributeError when the attribute does not exist.