Skip to content

Instantly share code, notes, and snippets.

@yaniv-aknin
Last active December 12, 2015 04:38
Show Gist options
  • Select an option

  • Save yaniv-aknin/4716162 to your computer and use it in GitHub Desktop.

Select an option

Save yaniv-aknin/4716162 to your computer and use it in GitHub Desktop.
When you read something like this, you go: "yuck!". When you write it, you're totally "dude, I'm so amazing!!1!".
def parse_with(parser):
def decor(func):
def __get__(self, instance, owner=None):
return self.__class__(instance, owner)
def __call__(self, *args, **kwargs):
params = parser.parse_args()
if self.instance:
return func(self.instance, params, *args, **kwargs)
return func(params, *args, **kwargs)
def __init__(self, instance=None, owner=None):
self.instance = instance
self.owner = owner
__dict__ = {"__get__": __get__, "__call__": __call__, "__init__": __init__, "__doc__":
func.__doc__, "__module__": func.__module__, "__name__": func.__name__}
return type(func.__name__, (object,), __dict__)()
return decor
from omnidecorator import parse_with
class MockParser(object):
def parse_args(self):
return 'RESULTS'
@parse_with(MockParser())
def foo(result):
assert result == 'RESULTS'
@parse_with(MockParser())
def bar(result, argument):
assert result == 'RESULTS'
assert argument == 'ARGUMENT'
foo()
bar('ARGUMENT')
class Spam(object):
@parse_with(MockParser())
def foo(self, result):
assert result == 'RESULTS'
return self
@parse_with(MockParser())
def bar(self, result, argument):
assert result == 'RESULTS'
assert argument == 'ARGUMENT'
return self
@parse_with(MockParser())
@classmethod
def qux(cls, result):
assert result == 'RESULTS'
return cls
instance = Spam()
assert instance.foo() is instance
assert instance.bar('ARGUMENT') is instance
assert Spam.qux() is Spam
@yaniv-aknin
Copy link
Copy Markdown
Author

(p.s.: the idea is to make a decorator which alters the arguments of the decorated function and can run on a function, classmethod or instancemethod)

@yaniv-aknin
Copy link
Copy Markdown
Author

Limitations of this implementation:

  • when decorating classmethods and staticmethods, @parse_with must appear immediately above the @classmethod/@staticmethod decorator
  • in a chain of several decorators on a method (any kind), @parse_with must be the first decorator at the top, or it won't be getattributed and its __get__ method won't be called.

Solutions to these issues will be highly appreciated.

@ncoghlan
Copy link
Copy Markdown

ncoghlan commented Feb 7, 2013

Neat hack, but as you imply, simply applying decorators after class method/staticmethod and having a way to explicitly tell the decorator to ignore the first parameter is rather more comprehensible than automagically ignoring it :)

Putting init last instead of first is a bit hard to read, and you also want a functools.wrap(func)() at the end of your decor implementation.

If you could explain how to use this to solve the problem of using functools.partial to define a method implementation (where the instance is still added on the left, but all new positional call args are appended on the right), that may make it's coolness more apparent.

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