diff --git a/python-dict-attribute/README.md b/python-dict-attribute/README.md new file mode 100644 index 0000000000..5f0914c2b4 --- /dev/null +++ b/python-dict-attribute/README.md @@ -0,0 +1,3 @@ +# Using Python's `.__dict__` to Work With Attributes + +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/). diff --git a/python-dict-attribute/class_inheritance.py b/python-dict-attribute/class_inheritance.py new file mode 100644 index 0000000000..a7282faa4d --- /dev/null +++ b/python-dict-attribute/class_inheritance.py @@ -0,0 +1,16 @@ +class Parent: + def __init__(self): + self.parent_attr = "parent" + + +class Child(Parent): + def __init__(self): + super().__init__() + self.child_attr = "child" + + +parent = Parent() +print(parent.__dict__) + +child = Child() +print(child.__dict__) diff --git a/python-dict-attribute/config_v1.py b/python-dict-attribute/config_v1.py new file mode 100644 index 0000000000..f5e06f1f86 --- /dev/null +++ b/python-dict-attribute/config_v1.py @@ -0,0 +1,16 @@ +class Config: + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + update = __init__ + + def __str__(self): + return str(self.__dict__) + + +config = Config(theme="light", font_size=12, language="English") +print(config) + +user = {"theme": "dark", "font_size": 14, "language": "Spanish"} +config.update(**user) +print(config) diff --git a/python-dict-attribute/config_v2.py b/python-dict-attribute/config_v2.py new file mode 100644 index 0000000000..aff8422edd --- /dev/null +++ b/python-dict-attribute/config_v2.py @@ -0,0 +1,33 @@ +class Config: + def __init__(self, name): + self.name = name + + def set_option(self, key, value): + self.__dict__[key] = value + + def get_option(self, key): + return self.__dict__.get(key, None) + + def remove_option(self, key): + if key in self.__dict__: + del self.__dict__[key] + # self.__dict__.pop(key) + print(f"'{key}' removed!") + else: + print(f"'{key}' does not exist.") + + def clear(self): + self.__dict__.clear() + print("All options removed!") + + +conf = Config("GUI App") +conf.set_option("theme", "dark") +conf.set_option("size", "200x400") +print(conf.__dict__) +conf.remove_option("size") +print(conf.__dict__) +conf.remove_option("autosave") +print(conf.__dict__) +conf.clear() +print(conf.__dict__) diff --git a/python-dict-attribute/config_v3.py b/python-dict-attribute/config_v3.py new file mode 100644 index 0000000000..5a86eb8b97 --- /dev/null +++ b/python-dict-attribute/config_v3.py @@ -0,0 +1,33 @@ +class Config: + def __init__(self, name): + self.name = name + + def set_option(self, key, value): + setattr(self, key, value) + + def get_option(self, key): + return getattr(self, key, None) + + def remove_option(self, key): + if hasattr(self, key): + delattr(self, key) + print(f"'{key}' removed!") + else: + print(f"'{key}' does not exist.") + + def clear(self): + for key in list(self.__dict__.keys()): + delattr(self, key) + print("All options removed!") + + +conf = Config("GUI App") +conf.set_option("theme", "dark") +conf.set_option("size", "200x400") +print(conf.__dict__) +conf.remove_option("size") +print(conf.__dict__) +conf.remove_option("autosave") # Raises KeyError +print(conf.__dict__) +conf.clear() +print(conf.__dict__) diff --git a/python-dict-attribute/demo.py b/python-dict-attribute/demo.py new file mode 100644 index 0000000000..bf80310209 --- /dev/null +++ b/python-dict-attribute/demo.py @@ -0,0 +1,13 @@ +class DemoClass: + class_attr = "This is a class attribute" + + def __init__(self): + self.instance_attr = "This is an instance attribute" + + def method(self): + return "This is a method" + + +print(DemoClass.__dict__) +demo_object = DemoClass() +print(demo_object.__dict__) diff --git a/python-dict-attribute/fibonacci.py b/python-dict-attribute/fibonacci.py new file mode 100644 index 0000000000..f194c2d157 --- /dev/null +++ b/python-dict-attribute/fibonacci.py @@ -0,0 +1,27 @@ +import time + + +def fibonacci_of_v1(n): + if n <= 1: + return n + return fibonacci_of_v1(n - 1) + fibonacci_of_v1(n - 2) + + +start = time.perf_counter() +fibonacci_of_v1(35) +end = time.perf_counter() +print(f"{end - start:.3f} seconds") + + +def fibonacci_of_v2(n): + cache = fibonacci_of_v2.__dict__.setdefault("cache", {}) + if n in cache: + return cache[n] + cache[n] = n if n <= 1 else fibonacci_of_v2(n - 1) + fibonacci_of_v2(n - 2) + return cache[n] + + +start = time.perf_counter() +fibonacci_of_v2(35) +end = time.perf_counter() +print(f"{end - start:.3f} seconds") diff --git a/python-dict-attribute/person.py b/python-dict-attribute/person.py new file mode 100644 index 0000000000..1640edb917 --- /dev/null +++ b/python-dict-attribute/person.py @@ -0,0 +1,29 @@ +class Person: + def __init__(self, first_name, last_name, age): + self.first_name = first_name + self.last_name = last_name + self.age = age + + def __str__(self): + return "{first_name} {last_name} is {age} years old".format( + **self.__dict__ + ) + + def __repr__(self): + return "{cls}('{first_name}', '{last_name}', {age})".format( + cls=type(self).__name__, + **self.__dict__, + ) + + def as_dict(self): + return self.__dict__ + + def as_tuple(self): + return tuple(self.__dict__.values()) + + +john = Person("John", "Doe", 30) +print(repr(john)) +print(john) +print(john.as_dict()) +print(john.as_tuple()) diff --git a/python-dict-attribute/record.py b/python-dict-attribute/record.py new file mode 100644 index 0000000000..6c770ab5fc --- /dev/null +++ b/python-dict-attribute/record.py @@ -0,0 +1,48 @@ +import logging + +logging.basicConfig(level=logging.INFO, format="%(message)s") + + +class Record: + def __init__(self, **fields): + logging.info(f"[INIT] Creating record with fields: {fields}") + self.__dict__.update(fields) + + def __getattribute__(self, key): + if key == "__dict__": + return super().__getattribute__(key) + value = super().__getattribute__(key) + logging.info(f"[GET] Accessing '{key}' → {value}") + return value + + def __setattr__(self, key, value): + if key in self.__dict__: + logging.info(f"[UPDATE] Modifying '{key}' → {value}") + else: + logging.info(f"[SET] Creating '{key}' → {value}") + self.__dict__[key] = value + + def __delattr__(self, key): + if key in self.__dict__: + logging.info(f"[DEL] Deleting '{key}'") + del self.__dict__[key] + else: + logging.warning( + f"[DEL] Attempted to delete non-existent field '{key}'" + ) + + +jane = Record(first_name="Jane", last_name="Doe", age=25) + +# Access +print(jane.first_name) +print(jane.age) + +# Mutations +jane.age = 26 +jane.job = "Software Engineer" +print(jane.__dict__) + +# Deletion +del jane.age +print(jane.__dict__) diff --git a/python-dict-attribute/salary.py b/python-dict-attribute/salary.py new file mode 100644 index 0000000000..9b503d423c --- /dev/null +++ b/python-dict-attribute/salary.py @@ -0,0 +1,14 @@ +class Employee: + def __init__(self, name, department, salary): + self.name = name + self.department = department + self.salary = salary + + def give_raise(self, amount): + self.salery = self.salary + amount # Typo here: self.salery + + +john = Employee("John", "Engineering", 70000) +john.give_raise(5000) +print(john.salary) +print(john.__dict__) diff --git a/python-dict-attribute/track_calls.py b/python-dict-attribute/track_calls.py new file mode 100644 index 0000000000..a2e529f894 --- /dev/null +++ b/python-dict-attribute/track_calls.py @@ -0,0 +1,10 @@ +def track_calls(): + track_calls.__dict__["calls"] = track_calls.__dict__.get("calls", 0) + 1 + print(f"Calls: {track_calls.calls}") + + +track_calls() +track_calls() +track_calls() + +print(track_calls.calls)