Learn What Attributes Are in Python: Absolute Beginners Tutorial

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.

python
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."

Note

__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.

code builder click a token to place it

Build the correct statement to set a name instance attribute inside __init__:

your code will appear here...
name cls self = . __init__
Why: Instance attributes are set using 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.

python
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.

Pro Tip

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 = value creates 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
spot the bug click the line that contains the bug

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.

1 class Dog:
2 def __init__(self, name, breed):
3 self.name = name
4 breed = self.breed
5
6 rex = Dog("Rex", "German Shepherd")
The fix: Change 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.

python
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.

Watch Out

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.

Attribute lookup chain — Python searches instance, then class, then parent classes before raising AttributeError.

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.

  1. Define a class with an __init__ method

    Create a class using the class keyword and define an __init__ method. Inside __init__, assign values using self.attribute_name = value. Each assignment creates an instance attribute that will exist on every object created from this class.

  2. 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".

  3. 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 to instance.attribute creates an instance attribute that shadows the class one only for that object.

  4. Use getattr, setattr, hasattr, and delattr

    When 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 with getattr(obj, name, default), write with setattr(obj, name, value), and remove with delattr(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

  1. 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.
  2. Instance attributes are defined inside methods with self and 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.
  3. The four built-in attribute functions — hasattr, getattr, setattr, and delattr — 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.

check your understanding question 1 of 5

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.