Skip to content

Commit a0f3307

Browse files
authored
Merge pull request #654 from realpython/python-dict-attribute
Sample code for the article on `.__dict__`
2 parents 2913668 + 171e948 commit a0f3307

File tree

11 files changed

+242
-0
lines changed

11 files changed

+242
-0
lines changed

python-dict-attribute/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Using Python's `.__dict__` to Work With Attributes
2+
3+
This folder provides the code examples for the Real Python tutorial [Using Python's `.__dict__` to Work With Attributes](https://realpython.com/python-dict-attribute/).
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Parent:
2+
def __init__(self):
3+
self.parent_attr = "parent"
4+
5+
6+
class Child(Parent):
7+
def __init__(self):
8+
super().__init__()
9+
self.child_attr = "child"
10+
11+
12+
parent = Parent()
13+
print(parent.__dict__)
14+
15+
child = Child()
16+
print(child.__dict__)

python-dict-attribute/config_v1.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Config:
2+
def __init__(self, **kwargs):
3+
self.__dict__.update(kwargs)
4+
5+
update = __init__
6+
7+
def __str__(self):
8+
return str(self.__dict__)
9+
10+
11+
config = Config(theme="light", font_size=12, language="English")
12+
print(config)
13+
14+
user = {"theme": "dark", "font_size": 14, "language": "Spanish"}
15+
config.update(**user)
16+
print(config)

python-dict-attribute/config_v2.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Config:
2+
def __init__(self, name):
3+
self.name = name
4+
5+
def set_option(self, key, value):
6+
self.__dict__[key] = value
7+
8+
def get_option(self, key):
9+
return self.__dict__.get(key, None)
10+
11+
def remove_option(self, key):
12+
if key in self.__dict__:
13+
del self.__dict__[key]
14+
# self.__dict__.pop(key)
15+
print(f"'{key}' removed!")
16+
else:
17+
print(f"'{key}' does not exist.")
18+
19+
def clear(self):
20+
self.__dict__.clear()
21+
print("All options removed!")
22+
23+
24+
conf = Config("GUI App")
25+
conf.set_option("theme", "dark")
26+
conf.set_option("size", "200x400")
27+
print(conf.__dict__)
28+
conf.remove_option("size")
29+
print(conf.__dict__)
30+
conf.remove_option("autosave")
31+
print(conf.__dict__)
32+
conf.clear()
33+
print(conf.__dict__)

python-dict-attribute/config_v3.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Config:
2+
def __init__(self, name):
3+
self.name = name
4+
5+
def set_option(self, key, value):
6+
setattr(self, key, value)
7+
8+
def get_option(self, key):
9+
return getattr(self, key, None)
10+
11+
def remove_option(self, key):
12+
if hasattr(self, key):
13+
delattr(self, key)
14+
print(f"'{key}' removed!")
15+
else:
16+
print(f"'{key}' does not exist.")
17+
18+
def clear(self):
19+
for key in list(self.__dict__.keys()):
20+
delattr(self, key)
21+
print("All options removed!")
22+
23+
24+
conf = Config("GUI App")
25+
conf.set_option("theme", "dark")
26+
conf.set_option("size", "200x400")
27+
print(conf.__dict__)
28+
conf.remove_option("size")
29+
print(conf.__dict__)
30+
conf.remove_option("autosave") # Raises KeyError
31+
print(conf.__dict__)
32+
conf.clear()
33+
print(conf.__dict__)

python-dict-attribute/demo.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class DemoClass:
2+
class_attr = "This is a class attribute"
3+
4+
def __init__(self):
5+
self.instance_attr = "This is an instance attribute"
6+
7+
def method(self):
8+
return "This is a method"
9+
10+
11+
print(DemoClass.__dict__)
12+
demo_object = DemoClass()
13+
print(demo_object.__dict__)

python-dict-attribute/fibonacci.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import time
2+
3+
4+
def fibonacci_of_v1(n):
5+
if n <= 1:
6+
return n
7+
return fibonacci_of_v1(n - 1) + fibonacci_of_v1(n - 2)
8+
9+
10+
start = time.perf_counter()
11+
fibonacci_of_v1(35)
12+
end = time.perf_counter()
13+
print(f"{end - start:.3f} seconds")
14+
15+
16+
def fibonacci_of_v2(n):
17+
cache = fibonacci_of_v2.__dict__.setdefault("cache", {})
18+
if n in cache:
19+
return cache[n]
20+
cache[n] = n if n <= 1 else fibonacci_of_v2(n - 1) + fibonacci_of_v2(n - 2)
21+
return cache[n]
22+
23+
24+
start = time.perf_counter()
25+
fibonacci_of_v2(35)
26+
end = time.perf_counter()
27+
print(f"{end - start:.3f} seconds")

python-dict-attribute/person.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class Person:
2+
def __init__(self, first_name, last_name, age):
3+
self.first_name = first_name
4+
self.last_name = last_name
5+
self.age = age
6+
7+
def __str__(self):
8+
return "{first_name} {last_name} is {age} years old".format(
9+
**self.__dict__
10+
)
11+
12+
def __repr__(self):
13+
return "{cls}('{first_name}', '{last_name}', {age})".format(
14+
cls=type(self).__name__,
15+
**self.__dict__,
16+
)
17+
18+
def as_dict(self):
19+
return self.__dict__
20+
21+
def as_tuple(self):
22+
return tuple(self.__dict__.values())
23+
24+
25+
john = Person("John", "Doe", 30)
26+
print(repr(john))
27+
print(john)
28+
print(john.as_dict())
29+
print(john.as_tuple())

python-dict-attribute/record.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import logging
2+
3+
logging.basicConfig(level=logging.INFO, format="%(message)s")
4+
5+
6+
class Record:
7+
def __init__(self, **fields):
8+
logging.info(f"[INIT] Creating record with fields: {fields}")
9+
self.__dict__.update(fields)
10+
11+
def __getattribute__(self, key):
12+
if key == "__dict__":
13+
return super().__getattribute__(key)
14+
value = super().__getattribute__(key)
15+
logging.info(f"[GET] Accessing '{key}' → {value}")
16+
return value
17+
18+
def __setattr__(self, key, value):
19+
if key in self.__dict__:
20+
logging.info(f"[UPDATE] Modifying '{key}' → {value}")
21+
else:
22+
logging.info(f"[SET] Creating '{key}' → {value}")
23+
self.__dict__[key] = value
24+
25+
def __delattr__(self, key):
26+
if key in self.__dict__:
27+
logging.info(f"[DEL] Deleting '{key}'")
28+
del self.__dict__[key]
29+
else:
30+
logging.warning(
31+
f"[DEL] Attempted to delete non-existent field '{key}'"
32+
)
33+
34+
35+
jane = Record(first_name="Jane", last_name="Doe", age=25)
36+
37+
# Access
38+
print(jane.first_name)
39+
print(jane.age)
40+
41+
# Mutations
42+
jane.age = 26
43+
jane.job = "Software Engineer"
44+
print(jane.__dict__)
45+
46+
# Deletion
47+
del jane.age
48+
print(jane.__dict__)

python-dict-attribute/salary.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class Employee:
2+
def __init__(self, name, department, salary):
3+
self.name = name
4+
self.department = department
5+
self.salary = salary
6+
7+
def give_raise(self, amount):
8+
self.salery = self.salary + amount # Typo here: self.salery
9+
10+
11+
john = Employee("John", "Engineering", 70000)
12+
john.give_raise(5000)
13+
print(john.salary)
14+
print(john.__dict__)

0 commit comments

Comments
 (0)