Skip to content

Instantly share code, notes, and snippets.

@rmariano
Created April 28, 2024 14:30
Show Gist options
  • Save rmariano/d11bed8469950795b2cc9c36159bb1a9 to your computer and use it in GitHub Desktop.
Save rmariano/d11bed8469950795b2cc9c36159bb1a9 to your computer and use it in GitHub Desktop.
"""An example of a descriptor with a ``__delete__()`` method.
The code is for illustration purposes only, and it does not correspond to any
actual implementation.
"""
class ProtectedAttribute:
"""A class attribute that can be protected against deletion"""
def __set_name__(self, owner, name):
self.name = name
def __set__(self, instance, value):
instance.__dict__[self.name] = value
def __delete__(self, instance):
raise AttributeError(f"Can't delete {self.name} for {instance!s}")
class ProtectedUser:
"""
>>> usr = ProtectedUser('jsmith', '127.0.0.1')
>>> usr.username
'jsmith'
>>> del usr.username
Traceback (most recent call last):
...
AttributeError: Can't delete username for ProtectedUser[jsmith]
>>> usr.location
'127.0.0.1'
>>> del usr.location
>>> usr.location
Traceback (most recent call last):
...
AttributeError: 'ProtectedUser' object has no attribute 'location'
"""
username = ProtectedAttribute()
def __init__(self, username, location):
self.username = username
self.location = location
def __str__(self):
return f"{self.__class__.__name__}[{self.username}]"
if __name__ == '__main__':
import doctest
doctest.testmod()
class Resolution:
"""Represents the resolution for a video display. In case there is no
resolution set, return a default value, previously indicated.
"""
def __init__(self, attr_name, default_resolution):
self.attr_name = attr_name
self.default_resolution = default_resolution
def __get__(self, instance, owner):
if instance is None:
return self
return self.default_resolution
class VideoDriver:
"""Contains multiple display devices, each one with a resolution
configured. If a resolution is not set for a device, return a default one,
provided by this class, as a fallback.
>>> media = VideoDriver()
>>> media.tv
(1024, 768)
>>> media.tv = (4096, 2160)
>>> media.tv
(4096, 2160)
>>> del media.tv
>>> media.tv
(1024, 768)
>>> media.screen
(1920, 1080)
>>> VideoDriver.tv # doctest: +ELLIPSIS
<__main__.Resolution object at 0x...>
"""
tv = Resolution('tv', (1024, 768))
screen = Resolution('screen', (1920, 1080))
if __name__ == '__main__':
import doctest
doctest.testmod()
class TracedProperty:
"""Keep count of how many times an attribute changed its value"""
def __set_name__(self, owner, name):
self.name = name
self.count_name = f'count_{name}'
def __set__(self, instance, value):
try:
current_value = instance.__dict__[self.name]
except KeyError:
instance.__dict__[self.count_name] = 0
else:
if current_value != value:
instance.__dict__[self.count_name] += 1
instance.__dict__[self.name] = value
class Traveller:
"""
>>> tourist = Traveller('John Smith')
>>> tourist.city = 'Barcelona'
>>> tourist.country = 'Spain'
>>> tourist.count_city
0
>>> tourist.count_country
0
>>> tourist.city = 'Stockholm'
>>> tourist.country = 'Sweden'
>>> tourist.count_city
1
>>> tourist.count_country
1
>>> tourist.city = 'Gothenburg'
>>> tourist.count_city
2
>>> tourist.count_country
1
>>> tourist.country = 'Sweden'
>>> tourist.count_country
1
"""
city = TracedProperty()
country = TracedProperty()
def __init__(self, name):
self.name = name
if __name__ == '__main__':
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment