Skip to content

Instantly share code, notes, and snippets.

@Skinner927
Last active December 30, 2018 00:47
Show Gist options
  • Save Skinner927/b717574a51713bc4208e88182b9735b7 to your computer and use it in GitHub Desktop.
Save Skinner927/b717574a51713bc4208e88182b9735b7 to your computer and use it in GitHub Desktop.
Python static property using a non-data descriptor
"""
This is an example of how to create a static property using a
non-data descriptor.
https://docs.python.org/2/howto/descriptor.html
This works in python >= 2.3 including 3.x.
In this example the __get_default() method is called the first time
we need to access Widget.default. The __get_default method clobbers
the descriptor and sets the new default Widget directly on the class.
This is so subsequent calls use the same default object.
The documentation will note this, but it's important to remember that
a non-data descriptor can be overridden by the instance dictionary, but
a data descriptor (has a __set__ method) will not be overridden so odd
things may happen if you define a __set__ method.
"""
import time
class Widget(object):
@classmethod
def __get_default(cls):
print('Making default') # Should only print once
cls.default = cls('Default {}'.format(time.time()), 'root')
return cls.default
# This is simply building a class and instantiating it.
# We only need the __get__ method for a non-data descriptor.
default = type('WidgetDefaultGetter', (object,), {
# See: https://docs.python.org/2/reference/datamodel.html#object.__get__
'__get__': lambda self, instance, type=None: type.__get_default()
})()
def __init__(self, name, parent=None):
if not parent:
# Here we use the getter oblivious to the fact it's a static getter
parent = Widget.default
# Some sanity that it can be accessed
assert Widget.default is self.default
self.name = name
self.parent = parent
def __str__(self):
return '{} -> {}'.format(self.parent, self.name)
# Run our example
print(Widget('First {}'.format(time.time())))
time.sleep(1)
print(Widget('Second {}'.format(time.time())))
# Output
'''
Making default
root -> Default 1546129640.722508 -> First 1546129640.7224388
root -> Default 1546129640.722508 -> Second 1546129641.722878
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment