Created
January 1, 2014 04:14
-
-
Save zpencerq/8204998 to your computer and use it in GitHub Desktop.
Was reading http://www.dzautner.com/meta-programming-javascript-using-proxies/ and decided to make the examples in Python using magic methods instead of a GetProxy object.
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
class Pipe(object): | |
def __init__(self, value): | |
self.pipe = [] | |
self.value = value | |
def __getattr__(self, name): | |
if name == 'get': | |
return lambda:reduce(lambda x, y: y(x), self.pipe, self.value) | |
self.pipe.append(globals()[name]) | |
return self | |
total = lambda x: sum(x) | |
double = lambda x: x*2 | |
reverseInt = lambda x: int(''.join(reversed(str(x)))) | |
countDigits = lambda x: {int(i): str(x).count(i) for i in str(x)} | |
def boom(n): | |
return n**n | |
print Pipe([1,2,3]).total.boom.double.reverseInt.countDigits.get() |
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
from functools import partial | |
operators = ["==", ">", "<", "!="] | |
class Repository(object): | |
def __init__(self, entities): | |
self.entities = entities | |
self.key = None | |
self.operator = None | |
self.__getitem__ = self._set_operator | |
def __getitem__(self, name): | |
if not self.operator and name in operators: | |
self.operator = name | |
else: | |
temp, self.operator = self.operator, None | |
self = self.filter(temp if temp else "==", name) | |
return self | |
def __getattr__(self, name): | |
if name == 'get': | |
return self.entities.pop() if len(self.entities) == 1 else self.entities | |
self.key = name | |
return self | |
def filter_entities(self, entity, key, operator, comparer): | |
if operator == "==": | |
return entity[key] == comparer | |
if operator == "<": | |
return entity[key] < int(comparer) | |
if operator == ">": | |
return entity[key] > int(comparer) | |
if operator == "!=": | |
return entity[key] != comparer | |
return False | |
def filter(self, operator, comparer): | |
results = filter(partial(self.filter_entities, comparer=comparer, operator=operator, key=self.key), self.entities) | |
return Repository(results) | |
xmas_list = Repository([ | |
{ | |
"name": "Daniel", | |
"age": 12, | |
"wants": "a dog", | |
}, | |
{ | |
"name": "Julia", | |
"age": 8, | |
"wants": "a bottle of rum" | |
}, | |
{ | |
"name": "Vitaly", | |
"age": float("inf"), | |
"wants": "a dog" | |
}, | |
{ | |
"name": "Ina", | |
"age": 20, | |
"wants": "Vitaly" | |
} | |
]); | |
print xmas_list.wants['a dog'].get # [{'wants': 'a dog', 'age': 12, 'name': 'Daniel'}, {'wants': 'a dog', 'age': 2020200, 'name': 'Vitaly'}] | |
print xmas_list.age['<'][12].get # {'wants': 'a bottle of rum', 'age': 8, 'name': 'Julia'} | |
print xmas_list.wants['a dog'].age[">"][12].get # {'wants': 'a dog', 'age': 2020200, 'name': 'Vitaly'} | |
print xmas_list.wants['a dog'].age[">"][12].get['name'] # Vitaly | |
print xmas_list.wants[ | |
xmas_list.wants['a dog'].age[">"][12].get['name'] | |
].get # {'wants': 'Vitaly', 'age': 20, 'name': 'Ina'} |
Wow! Didn't really expect anyone to see this.
A couple of things to note:
- I think using some sort of Proxy would make the Repository example much cleaner in Python (instead of just hackingly tracking the operator, as I did).
- Python differentiates between getting an item (obj[key] per getitem) vs. getting an attribute (obj.key per getattr).
However, Python doesn't support multi-line anonymous functions so this use isn't as awesome as it would be in JS or Ruby.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Glad you enjoyed my article!
Your result is super cool! Had no idea such a straightforward translation from JS is possible with Python.