The setattr(object, name, value) function dynamically assigns a value to an object's attribute at runtime using a string identifier.
Reflection & Metaprogramming: Calling setattr(obj, "attr", val) is the dynamic programmatic equivalent of static dot notation (obj.attr = val). If the attribute already exists on the object, its value is overwritten; if it does not exist, a new instance attribute is created. To read or verify attributes dynamically, use companion built-in functions like getattr() and hasattr(), or remove them with delattr().
The setattr() function takes three arguments and returns None:
setattr(object, name, value)
| Parameter | Type | Description |
|---|---|---|
object |
Any mutable object | The target instance or class whose attribute will be added or updated. |
name |
str |
The attribute name as a string identifier. Passing other types raises a TypeError. |
value |
Any object | The value assigned to the attribute (numbers, strings, functions, or None). |
| Return Value | None |
Modifies the object state in-place and always returns None. |
Use setattr() to add new attributes or overwrite existing ones on an instance:
class Animal:
species = "carnivores"
def __init__(self, name: str, age: int):
self.name = name
self.age = age
tiger = Animal("Ronald", 5)
# 1. Add new attribute dynamically
setattr(tiger, "height", 3.5)
print("New attribute height:", tiger.height)
# 2. Update existing attribute
setattr(tiger, "age", 6)
print("Updated age:", tiger.age)
# 3. Set attribute to None
setattr(tiger, "age", None)
print("Age set to None:", tiger.age)
Output:
New attribute height: 3.5
Updated age: 6
Age set to None: None
setattr() 🔝Dot notation (obj.attr = val) requires fixed identifiers at compile time. setattr() allows dynamic string identifiers at runtime:
class UserProfile:
pass
user = UserProfile()
fields = {"email": "dev@example.com", "status": "active", "score": 95}
# Dynamically assign attributes from dictionary keys
for k, v in fields.items():
setattr(user, k, v)
print("User:", user.email, user.status, user.score)
Output:
User: dev@example.com active 95
Passing a class object to setattr() updates class-level defaults. Passing an instance updates only that specific instance:
class Server:
timeout = 30
s1 = Server()
s2 = Server()
# Instance attribute update
setattr(s1, "timeout", 10)
print("s1 timeout:", s1.timeout)
print("s2 timeout (default):", s2.timeout)
# Class attribute update
setattr(Server, "timeout", 60)
print("s2 after class update:", s2.timeout)
Output:
s1 timeout: 10
s2 timeout (default): 30
s2 after class update: 60
getattr() Synergy 🔝setattr() allows storing strings containing hyphens or spaces that cannot be written with dot notation:
class HeaderBag:
pass
headers = HeaderBag()
setattr(headers, "content-type", "application/json")
setattr(headers, "x-api-key", "token_123")
# Read using companion getattr()
ct = getattr(headers, "content-type")
print("Retrieved header:", ct)
print("Object dictionary:", headers.__dict__)
Output:
Retrieved header: application/json
Object dictionary: {'content-type': 'application/json', 'x-api-key': 'token_123'}
__slots__ 🔝Python prevents arbitrary attribute injection on built-in types and slotted classes:
# 1. Built-in types are immutable and protected
try:
setattr(42, "flag", True)
except TypeError as err:
print("Built-in exception caught:", err)
# 2. Slotted classes reject unlisted attributes
class Point:
__slots__ = ("x", "y")
pt = Point()
setattr(pt, "x", 10)
try:
setattr(pt, "z", 99)
except AttributeError as err:
print("Slots AttributeError:", err)
Output:
Built-in exception caught: 'int' object has no attribute 'flag'
Slots AttributeError: 'Point' object has no attribute 'z'
Populate configuration objects dynamically from parsed environment dictionaries:
class DatabaseConfig:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
cfg = DatabaseConfig(host="localhost", port=5432, ssl=True)
print("Config host:", cfg.host, "Port:", cfg.port)
Output:
Config host: localhost Port: 5432
Replace external API service calls with mock lambdas during automated testing:
class PaymentService:
def charge(self, amount: float) -> str:
return "Real payment processed"
service = PaymentService()
setattr(service, "charge", lambda amt: f"Mock charged {amt}")
print("Patched charge:", service.charge(100.0))
Output:
Patched charge: Mock charged 100.0
__setattr__: If you override __setattr__ in your class and call setattr(self, name, val) inside it, Python enters infinite recursion! Always delegate to super().__setattr__(name, val).
class AuditedModel:
def __setattr__(self, name, value):
super().__setattr__(name, value)
model = AuditedModel()
setattr(model, "active", True)
print("Safe assignment:", model.active)
Output:
Safe assignment: True
Practice hands-on drills, dictionary mapping, and mocking recipes in our companion Jupyter Notebook:
Explore interactive code cells, dynamically map nested dictionary structures, test __slots__ limits, and run self-validating assertions.
Run these unit checks directly in Python or your local environment to verify setattr() mechanics:
def test_setattr_mechanics():
class Car:
pass
c = Car()
setattr(c, "wheels", 4)
assert c.wheels == 4
setattr(c, "wheels", 6)
assert c.wheels == 6
setattr(c, "color", None)
assert c.color is None
setattr(c, "fuel-type", "diesel")
assert getattr(c, "fuel-type") == "diesel"
print("All setattr() unit assertions passed! 100% verified.")
test_setattr_mechanics()
Output:
All setattr() unit assertions passed! 100% verified.
Retrieves the value of a named attribute from an object, with optional default fallback.
Checks whether an object possesses a specific attribute, returning True or False.
Deletes a named attribute directly from an object instance.
Returns the __dict__ mapping for an object or module namespace.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.