Last active
May 4, 2017 07:23
-
-
Save verdimrc/a990bc5ca18180916685cff422157787 to your computer and use it in GitHub Desktop.
A Python property decorator that can chain decorated property.
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
#!/home/verdi/miniconda3/bin/python3.6 | |
''' | |
Demonstrate a property decorator that can chain decorated property. | |
For chaining to work, decoratee must be a plain function or a property with | |
fget attribute. | |
Sample outputs: | |
(py36) verdi@verdi-VirtualBox:/tmp$ ./haha.py | |
######## | |
class Test... | |
######## | |
deco.__call__(fget=<function Test.x at 0xb6f0a614>) | |
deco.__call__(fget=<function Test.x at 0xb6f0a614>) | |
deco.__call__(fget=<function Test._y at 0xb6f0a5cc>) | |
######## | |
class TTest(...) | |
######## | |
deco.__call__(fget=<function TTest.x at 0xb6f0a584>) | |
deco.__call__(fget=<__main__.deco object at 0xb6f183ec>) | |
deco.__call__(fget=<property object at 0xb6f28824>) | |
######## | |
t.x, t.y, t.x2 | |
######## | |
[decoratee == plain old function] deco(darg=100): name=x, <function Test.x at 0xb6f0a614>, val=10 | |
[decoratee == plain old function] deco(darg=200): name=y, <function Test._y at 0xb6f0a5cc>, val=20 | |
[decoratee == plain old function] deco(darg=102): name=x2, <function Test.x at 0xb6f0a614>, val=10 | |
results: 10 20 10 | |
######## | |
tt.x3, tt.y2 | |
######## | |
[decoratee == property or deco] deco(darg=103): name=x3, <__main__.deco object at 0xb6f183ec>, recursing... | |
[decoratee == plain old function] deco(darg=100): name=x, <function TTest.x at 0xb6f0a584>, val=11 | |
=> deco(darg=103): recurse ended, val=11 | |
[decoratee == property or deco] deco(darg=200): name=y2, <property object at 0xb6f28824>, recursing... | |
=> deco(darg=200): recurse ended, val=21 | |
results: 11 21 | |
y.setter invoked | |
[decoratee == property or deco] deco(darg=103): name=x3, <__main__.deco object at 0xb6f183ec>, recursing... | |
[decoratee == plain old function] deco(darg=100): name=x, <function TTest.x at 0xb6f0a584>, val=11 | |
=> deco(darg=103): recurse ended, val=11 | |
[decoratee == property or deco] deco(darg=200): name=y2, <property object at 0xb6f28824>, recursing... | |
=> deco(darg=200): recurse ended, val=44 | |
results: 11 44 | |
''' | |
class deco(object): | |
def __init__(self, darg=100): | |
self.darg = darg | |
def __call__(self, fget): | |
print(f'deco.__call__(fget={fget})') | |
self.fget = fget | |
return self | |
def __set_name__(self, owner, name): | |
# New since Python 3.6 | |
self.name = name | |
def __get__(self, inst, owner): | |
if not hasattr(self.fget, 'fget'): | |
print(f'[decoratee == plain old function] deco(darg={self.darg}): name={self.name}, {self.fget}, ', end='') | |
val = self.fget(inst) | |
print(f'val={val}') | |
else: | |
print(f'[decoratee == property or deco] deco(darg={self.darg}): name={self.name}, {self.fget}, recursing...') | |
#descriptor = self.__dict__['fget'] | |
#val = descriptor.__get__(inst, owner) | |
val = self.fget.__get__(inst, owner) | |
print(f' => deco(darg={self.darg}): recurse ended, val={val}') | |
return val | |
print('#' * 8) | |
print('class Test...') | |
print('#' * 8) | |
class Test(object): | |
@deco() | |
def x(self): | |
return 10 | |
x2 = deco(darg=102)(x.fget) | |
def _y(self): | |
return 20 | |
y = deco(darg=200)(_y) | |
print('\n' + '#' * 8) | |
print('class TTest(...)') | |
print('#' * 8) | |
class TTest(object): | |
def __init__(self): | |
self._y = 21 | |
@deco() | |
def x(self): | |
return 11 | |
x3 = deco(darg=103)(x) | |
@property | |
def y(self): | |
return self._y | |
@y.setter | |
def y(self, yy): | |
print("y.setter invoked") | |
self._y = yy | |
y2 = deco(darg=200)(y) | |
if __name__ == '__main__': | |
print('\n' + '#' * 8) | |
print('t.x, t.y, t.x2') | |
print('#' * 8) | |
t = Test() | |
print('results:', t.x, t.y, t.x2) | |
print('\n' + '#' * 8) | |
print('tt.x3, tt.y2') | |
print('#' * 8) | |
tt = TTest() | |
print('results:', tt.x3, tt.y2) | |
tt.y = 44 | |
print('results:', tt.x3, tt.y2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment