Skip to content

Instantly share code, notes, and snippets.

@L3viathan
Last active August 31, 2016 07:02
Show Gist options
  • Save L3viathan/6f2df79571d7788accd95cc646b379e1 to your computer and use it in GitHub Desktop.
Save L3viathan/6f2df79571d7788accd95cc646b379e1 to your computer and use it in GitHub Desktop.
Horrible abuse of Python's magic methods to make a more magic version of itemgetter/attrgetter
import operator as op
from functools import partial
class _getter(object):
def __init__(self, *, is_original=True):
self.is_original=is_original
self.__ops = []
def __call__(self, something):
''' Maybe eventually extend to act like methodcaller, but problems exist'''
if self.is_original:
return _getter(is_original=False)
for function in self.__ops:
something = function(something)
return something
def __getattr__(self, attr):
'''getter.foo'''
if attr.startswith('__'):
return super().__getattr__(self, attr)
if self.is_original:
return _getter(is_original=False).__getattr__(attr)
self.__ops.append(op.attrgetter(attr))
return self
def __getitem__(self, item):
'''getter[foo]'''
if self.is_original:
return _getter(is_original=False).__getitem__(item)
self.__ops.append(op.itemgetter(item))
return self
def __matmul__(self, other):
'''Not actually matmul. getter@function. Applies function.'''
if self.is_original:
return _getter(is_original=False).__matmul__(other)
self.__ops.append(other)
return self
def __eq__(self, other):
'''map to boolean if evaluates to True'''
if self.is_original:
return _getter(is_original=False).__eq__(other)
self.__ops.append(partial(op.eq, other))
return self
...
getter = _getter()
if __name__ == '__main__':
from random import randint
l = [(randint(0,20), randint(0,20)) for _ in range(10)]
print(l) # [(8, 0), (7, 8), (12, 8), (10, 13), (20, 18), (3, 20), (19, 7), (11, 18), (2, 16), (5, 0)]
print(sorted(l))
# [(2, 16), (3, 20), (5, 0), (7, 8), (8, 0), (10, 13), (11, 18), (12, 8), (19, 7), (20, 18)]
print(sorted(l, key=getter[1]))
# [(8, 0), (5, 0), (19, 7), (7, 8), (12, 8), (10, 13), (2, 16), (20, 18), (11, 18), (3, 20)]
class Bar():
def __init__(self):
self.n = (randint(1,20), randint(1, 20))
@property
def foo(self):
return self.n
def __repr__(self):
return 'foo: ' + str(self.n)
L = [Bar() for _ in range(7)]
print(L)
# [foo: (10, 16), foo: (17, 1), foo: (17, 11), foo: (6, 14), foo: (18, 18), foo: (2, 13), foo: (13, 8)]
# sorted(L) # fails, unorderable types: Bar() < Bar()
print(sorted(L, key=getter.foo[1]))
# [foo: (17, 1), foo: (13, 8), foo: (17, 11), foo: (2, 13), foo: (6, 14), foo: (10, 16), foo: (18, 18)]
@L3viathan
Copy link
Author

So.... I took this a step further.

It's now in the magic module of toolib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment