3 ms·
And here's a more magical version that wraps it with a decorator. If you're gonna do this I kind of like this way better, but I'm pretty sure your average pytho
by stormbrew 13y ago
And here's a more magical version that wraps it with a decorator. If you're gonna do this I kind of like this way better, but I'm pretty sure your average python programmer finds it obscene:
from pprint import pprint
def default_init(init_func):
arg_count = init_func.func_code.co_argcount
arg_vars = init_func.func_code.co_varnames[1:1+arg_count]
def wrap_init(self, *args, **kwargs):
idx = 0
for arg in arg_vars:
if arg in kwargs:
setattr(self, arg, kwargs[arg])
else:
setattr(self, arg, args[idx])
idx += 1
init_func(self, *args, **kwargs)
return wrap_init
class testing(object):
@default_init
def __init__(self, a, b, c):
pass
x = testing(1, 2, 3)
pprint(x.a)
pprint(x.b)
pprint(x.c)
y = testing(1, 2, c=3)
pprint(y.a)
pprint(y.b)
pprint(y.c)
[note: I'm aware this does not do even remotely a complete job as a decorator. Use at your own risk, it is a demonstration only.]
- reuven 13y agoVery nice; it does seems far more reasonable to implement this as a decorator than as an explicit function call __init__.
- stormbrew 13y agoOne thing I like a lot better about it in particular is that it doesn't reach into the stack frame, which strikes me as a very messy grab at internals people should never ever touch. The arity and name information from the compiled function object, however, has legitimate use in tooling and I suspect a lot of decorators do this sort of thing. It's an interesting balance between one being more magical in its use of the system (inspecting live stack frames) and the other being more magical in appearance (having a function with just pass in it actually do something).
- n0on3 13y agonice but it doesn't work if not all kwargs are passed..
- n0on3 13y agoHere is another version implemented as a decorator. Actually I’d also like not to use inspect, but didn’t find any nice way to get the kwargs default values without it, any suggestion? import inspect def autoinit(decorated_init): def _wrap(*args, **kwargs): obj, nargs= args[0], args[1:] names = decorated_init.func_code.co_varnames[1:len(nargs)+1] nargs = {k: nargs[names.index(k)] for k in names} kwa_keys = decorated_init.func_code.co_varnames[len(nargs)+1:] kwa_defaults = inspect.getargspec(decorated_init).defaults for k in kwa_keys: nargs[k] = kwargs[k] if (k in kwargs) else kwa_defaults[kwa_keys.index(k)] for k, v in nargs.iteritems(): setattr(obj, k, v) return decorated_init(*args, **kwargs) return _wrap if __name__ == '__main__': class Foo(): @autoinit def __init__(self, a, b, x=0, y=0): self.p = 'Hello, I am set inside the __init__' self.s = self.a + self.b + self.x + self.y f = Foo(1, 2, x=120, y=5) for param in 'abxyps': print param, '=>', getattr(f, param) f = Foo(31, 33, x=64) for param in 'abxyps': print param, '=>', getattr(f, param) f = Foo(7, 121) for param in 'abxyps': print param, '=>', getattr(f, param)
- deleted 13y ago[deleted]
- stormbrew 13y agoGood call. It's amazing how many things you have to be careful of when writing decorators.