Skip to content

Instantly share code, notes, and snippets.

@karanlyons
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karanlyons/a53eaa7a26f1bddbae83 to your computer and use it in GitHub Desktop.
Save karanlyons/a53eaa7a26f1bddbae83 to your computer and use it in GitHub Desktop.
PartialObject (as functools.partial is to functions)
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals
import inspect
from collections import OrderedDict
class PartialManager(type):
def __call__(cls, *args, **kwargs):
signature = inspect.getargspec(cls.__init__)
arg_names = signature.args[1:]
if signature.defaults:
arg_names = arg_names[:-len(signature.defaults)]
if (len(args) + sum(arg in kwargs for arg in arg_names)) >= len(arg_names):
return super(PartialManager, cls).__call__(*args, **kwargs)
else:
return getattr(cls, '__partialclass__', PartialObject)(cls, *args, **kwargs)
class PartialObject(object):
def __init__(self, cls, *args, **kwargs):
self.cls = cls
self.args = args
self.kwargs = kwargs
self.args, self.kwargs = self.modify(self.args, self.kwargs)
signature = inspect.getargspec(self.cls.__init__)
self.arg_names = signature.args[1:]
if signature.defaults:
self.arg_names = self.arg_names[:-len(signature.defaults)]
self.default_kwargs = OrderedDict(zip(signature.args[-len(signature.defaults):], signature.defaults))
else:
self.default_kwargs = OrderedDict()
def __call__(self, *args, **kwargs):
new_args = self.args + args
new_kwargs = self.kwargs.copy()
new_kwargs.update(kwargs)
new_args, new_kwargs = self.modify(new_args, new_kwargs)
return self.cls(*new_args, **new_kwargs)
def modify(self, args, kwargs):
return (args, kwargs)
def __unicode__(self):
applied = list(self.arg_names)[:len(self.args)]
kwargs = self.kwargs.copy()
for arg_name in self.arg_names:
if arg_name in kwargs:
del(kwargs[arg_name])
applied.append(arg_name)
for kwarg, default in self.default_kwargs.iteritems():
if kwarg in kwargs:
if kwargs[kwarg] != default:
applied.append(kwarg)
del(kwargs[kwarg])
applied.extend(kwargs.iterkeys())
return 'Partial %s (Applied: %s)' % (self.cls.__name__, ', '.join(applied) if applied else None)
def __str__(self):
return unicode(self).encode('utf-8')
def __repr__(self):
args = self.args[:]
kwargs = self.kwargs.copy()
args += tuple((kwargs.pop(arg_name) for arg_name in self.arg_names if arg_name in kwargs))
args = (
['%s' % repr(arg) for arg in args] +
['%s=%s' % (kwarg, repr(kwargs[kwarg])) for kwarg, default in self.default_kwargs.iteritems() if kwarg in kwargs and kwargs[kwarg] != default] +
['%s=%s' % (kwarg, repr(value)) for kwarg, value in kwargs.iteritems() if kwarg not in self.default_kwargs]
)
return '%s(%s%s)' % (self.__class__.__name__, self.cls.__name__, ', %s' % ', '.join(args) if args else '')
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals
from partial_object import PartialManager, PartialObject
class PartialTest(PartialObject):
def modify(self, args, kwargs):
'''
Allows supplying arguments out of order.
'''
if args and isinstance(args[0], int) and 'count' not in kwargs:
args = list(args)
kwargs['count'] = args.pop(0)
args = tuple(args)
return (args, kwargs)
class Test(object):
__metaclass__ = PartialManager
__partialclass__ = PartialTest
def __init__(self, name, count):
for i in xrange(count):
print(name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment