0

Is is possible to access the arguments which were passed to __init__, without explicitly having to store them?

e.g.

class thing(object):
  def __init__(self, name, data):
    pass # do something useful here

t = thing('test', [1,2,3,])
print t.__args__ # doesn't exist

>> ('test', [1,2,3])

The use-case for this is creating a super-class which can automatically store the arguments used to create an instance of a class derived from it, without having to pass all the arguments explicitly to the super's __init__. Maybe there's an easier way to do it!

4
  • I've explained various patterns of initializing objects in my answer here: stackoverflow.com/a/2353165/92493 Commented Jul 18, 2012 at 18:25
  • Thanks Otto but I don't believe any of those patterns are actually relevant to my question. Commented Jul 18, 2012 at 18:58
  • I assume you mean class thing rather than def thing Commented Jul 18, 2012 at 19:49
  • Oops sorry yes, changed it to a simpler example and typo'd in the process. Now fixed. Commented Jul 18, 2012 at 22:40

4 Answers 4

9

No, you have to store them. Otherwise they are gone after __init__() returns, as all local variables.

If you don't want to pass all arguments on explicitly, you can use **kwargs:

class Base(object):
    def __init__(self, name, data):
        # store name and data

class Derived(Base):
    def __init__(self, **kwargs):
        Base.__init__(self, **kwargs)

Derived(name="Peter", data=42)
Sign up to request clarification or add additional context in comments.

3 Comments

That's exactly what I'm doing at the moment, but I wondered whether there was a way which didn't rely on the author of the Derived class correctly passing all it's *args and **kwargs. Since Derived.__init__ hasn't returned during Base.__init__'s scope, is there a way of retrieving those locals?
@lost: In Python implementations supporting stack frames (CPython does), you can inspect the calling frames and extract their local variables, but you definitely don't want to go that route. I still don't understand what problem you are solving. Of course a dervied class has to call the base class' methods correctly. Everone has to.
Sure, but if you're trying to do provide a 'magic' base class so that derived classes "just work" wouldn't you rather that the derived class never even has to call a method? However, your answers have made me understand why something like __args__ can't exist, so thank you!
3

This is not entirely recommended, but here is a wrapper that automatically stores parameter variables:

from functools import wraps
def init_wrapper(f):
    @wraps(f)
    def wrapper(self, *args, **kwargs):
        func_parameters = f.func_code.co_varnames[1:f.func_code.co_argcount]

        #deal with default args
        diff = len(func_parameters) - len(args)
        if diff > 0:
            args += f.func_defaults[-diff:]

        #set instance variables
        for pos, arg in enumerate(func_parameters):
            print pos, arg
            setattr(self, arg, args[pos])

        f(self, *args, **kwargs) #not necessary to use return on __init__()
    return wrapper

Usage:

class A(object):
    @init_wrapper
    def __init__(self, a, b, c):
        print a + b + c

Example:

>>> a = A(1, 2, 3)
6
>>> a.a
1
>>> a.b
2
>>> a.c
3

1 Comment

Ah I was wondering it there was some way using the code objects. Thanks for the demo - and agree with the "not entirely recommended" caveat!
0

In a word: No.

What you could do is:

def __init__(self, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs

If you find yourself needing to do this a lot, you could also use a decorator to abstract the task.

Comments

-1

I think that you are looking for arbitrary argument lists and keyword arguments combined with super.__init__.

Give "Python's Super is nifty, but you can't use it" a read before you start down this path though.

3 Comments

Not downvoting, but it's not obvious how this helps.
Not only is the article not relevant, it contains some rather poor advice (such as to always pass **kwargs to super __init__)
Agree it doesn't appear to help. I can definitely pass arguments to super's __init__, but I'd rather avoid it (although to be fair that might not be clear from the original question). However you do link to Python's function calling syntax which I'd always wondered where it was properly documented :-(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.