Suppose a followers list needs usernames, but each follower’s full profile requires a server request. Loading every profile while creating the list wastes time and memory if most profiles are never opened. Lazy initialization keeps object creation cheap and fetches a profile only when its value is requested. section 9.4.1 section 9.4
Cache a profile with a property
class User: def __init__(self, username): self.username = username self._profile_data = None @property def profile_data(self): if self._profile_data is None: self._profile_data = self._get_profile_data() return self._profile_data def _get_profile_data(self): print('Fetching profile') return 'Extensive profile data' user = User('John') # No fetch print(user.profile_data) # Fetching profile; Extensive profile data print(user.profile_data) # Extensive profile data The property preserves dot-notation access. Its internally managed value starts as None; the first access fetches and stores the data, and later accesses return the stored value. section 9.4.3
An alternative is to leave the attribute unset in __init__ and override __getattr__. When an absent attribute is requested, __getattr__ can fetch its value, save it with setattr, and return it. Do not initialize that attribute to None in this version: an existing entry prevents this fallback from running. The property approach is generally clearer because its behavior is explicit; __getattr__ depends on understanding attribute resolution. section 9.4.2 section 9.4.4
Listing 9.7 Overriding __getattr__ in a class
class User:
def __init__(self, username):
self.username = username
print(f"### User {username} created")
def __getattr__(self, item):
print(f"__getattr__ called for {item}")
if item == "profile_data":
profile_data = self._get_profile_data()
setattr(self, item, profile_data)
return profile_data
def _get_profile_data(self):
# get the data from the server and load it into memory
print("*** Run the expensive operation")
fetched_data = "Extensive data, including thumbnail,
followers, etc."
return fetched_data
Inspect the __getattr__ alternative: it fetches profile_data only when requested, then stores it so the next access does not fetch again. section 9.4.2
Use this pattern when constructing many objects would otherwise trigger expensive work that only some objects need. The same consideration can apply to costly database-backed information. section 9.4.1 section 9.5.3


