Skip to content

Instantly share code, notes, and snippets.

@zpencerq
Created January 1, 2014 04:14
Show Gist options
  • Save zpencerq/8204998 to your computer and use it in GitHub Desktop.
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.
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()
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'}
@dzautner
Copy link

dzautner commented Jan 1, 2014

Glad you enjoyed my article!
Your result is super cool! Had no idea such a straightforward translation from JS is possible with Python.

@zpencerq
Copy link
Author

zpencerq commented Jan 1, 2014

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