Last active
December 30, 2018 00:47
-
-
Save Skinner927/b717574a51713bc4208e88182b9735b7 to your computer and use it in GitHub Desktop.
Python static property using a non-data descriptor
This file contains hidden or 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
""" | |
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