Created
September 26, 2023 07:19
-
-
Save nenetto/46e65ff249a3bc8dd17fa621c507eb12 to your computer and use it in GitHub Desktop.
Descriptors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Descriptor protocol | |
# Special objects with that show magic functionality when they are the type of | |
# other's class attribute. | |
## Methods | |
def __get__(self, obj, type = None) -> object: | |
""" | |
self: descriptor itself | |
obj: object the descriptor is attached (as attribute) to | |
type: type of the obj | |
""" | |
pass | |
def __set__(self, obj, value) -> None: | |
pass | |
def __delete__(self, obj) -> None: | |
pass | |
def __set_name__(self, owner, name): | |
""" | |
This is for python > 3.6 | |
name: is the name assigned as attribute | |
""" | |
pass | |
## Type of Descriptors | |
# If only __get__ -> Non-data descriptor | |
# If __get__ + __set__ / __delete__ -> Data descriptor | |
# ⛓️ The lookup chain | |
# When we do OBJECT.attribute/method: | |
# 1st) Data descriptor (__get__ + __set__ / __delete__): attribute.__get__() | |
# 2nd) OBJECT.__dict__['attribute/method'] | |
# 3rd) Non-Data descriptor (only __get__): attribute.__get__() | |
# 4th) type(OBJECT).__dict__['attribute/method'] # Search in the Class attributes | |
# 5th) type(OBJECT).__base__.__dict__['attribute/method'] # Search in the Base class attributes | |
## Example of use: Lazy attributes. | |
# Loads the attribute when it is first accessed | |
# lazy_properties.py | |
import time | |
class LazyProperty: | |
""" Non data descriptor for a lazy property | |
""" | |
def __init__(self, function): | |
self.function = function | |
self.name = function.__name__ | |
def __get__(self, obj, type=None) -> object: | |
obj.__dict__[self.name] = self.function(obj) # this is like call meaning_of_life(self), where self == obj | |
return obj.__dict__[self.name] | |
class DeepThought: | |
@LazyProperty | |
def meaning_of_life(self): | |
time.sleep(3) | |
return 42 | |
my_deep_thought_instance = DeepThought() # At this point, my_deep_thought_instance.meaning_of_life is a method | |
print(my_deep_thought_instance.meaning_of_life) # Step 1 (miss), Step 2 (miss), Step 3 (found! Non data descriptor) | |
print(my_deep_thought_instance.meaning_of_life) # Step 1 (miss), Step 2 (found!, already set) -> no execution of function, just attribute | |
print(my_deep_thought_instance.meaning_of_life) # At this point my_deep_thought_instance.meaning_of_life is an integer (42) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment