26

What is a way to extract arguments from __init__ without creating new instance. The code example:

class Super:
    def __init__(self, name):
        self.name = name

I am looking something like Super.__dict__.keys()type solution. Just to retrieve name argument information without adding any values. Is there such an option to do that?

3
  • Question is not clear. Do you mean you want to check value of name and decide if you want to create new instance or not? Commented Apr 25, 2016 at 19:56
  • I don't want to create instance at all. I want to introspect objects arguments. It is just like question "what arguments this object have". It is all about general introspection not about values. I changed question to make it a bit more understandable. Commented Apr 25, 2016 at 20:07
  • 1
    Instance is already created by the time __init__ gets called. See this answer stackoverflow.com/questions/674304/pythons-use-of-new-and-init Commented Apr 25, 2016 at 20:22

2 Answers 2

45

Update for Python 3.3+ (as pointed out by beeb in the comments)

You can use inspect.signature introduced in Python 3.3:

class Super:
    def __init__(self, name, kwarg='default'):
        print('instantiated')
        self.name = name

>>> import inspect
>>> inspect.signature(Super.__init__)
<Signature (self, name, kwarg='default')>

Original answer below

You can use inspect

>>> import inspect
>>> inspect.getargspec(Super.__init__)
ArgSpec(args=['self', 'name'], varargs=None, keywords=None, defaults=None)
>>> 

Edit: inspect.getargspec doesn't actually create an instance of Super, see below:

import inspect

class Super:
    def __init__(self, name):
        print 'instantiated'
        self.name = name

print inspect.getargspec(Super.__init__)

This outputs:

### Run test.a ###
ArgSpec(args=['self', 'name'], varargs=None, keywords=None, defaults=None)
>>> 

Note that instantiated never got printed.

Sign up to request clarification or add additional context in comments.

6 Comments

It looks like that it is what I was looking for. One additional question: Is there an option to get that result without "inspect" module. Something like Super.__dict__.keys solution if it is not, that means that inspect.getargspec() is like instance simulation that helps to retrieve arguments?
There are a bunch of answers for retrieving argument names out of a function - stackoverflow.com/questions/582056/… and it looks like inspect is the only way. Even using globals returns in a function call, which is not what you want. Incidentally, using inspect doesn't result in a function call, editing my answer for an example...
@Bahrom anyway to do this for a hierarchy of inheriting classes?
Actually, I already implemented it by travelling up the class.mro() and getting the init signature along the way, I used it to write a custom JSON encoder that doesn't encode members with default values, works like a charm. :)
DeprecationWarning: inspect.getargspec() is deprecated since Python 3.0, use inspect.signature() or inspect.getfullargspec()
|
2

A metaclass that stores the concrete __init__ parameters in a class field:

class ParameterReader(ABCMeta):
    def __init__(cls, *args, **kwargs):
        parameters = inspect.signature(cls.__init__).parameters
        parameters = {key: value for key, value in parameters.items() if key not in ['self', 'args', 'kwargs']}
        try:
            cls._init_parameters = cls.__bases__[0]._init_parameters.copy()
            cls._init_parameters.update(parameters)
        except AttributeError:
            cls._init_parameters = parameters

        super().__init__(*args, **kwargs)

_init_parameters can then be used within the class instance or outside of it:

class Fruit(metaclass=ParameterReader):
    def __init__(self, color):
        print(color)

class Corn(Fruit):
    def __init__(self, size, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print(size)
        print(self._init_parameters)

print(Corn._init_parameters)

Producing:

{'color': <Parameter "color">, 'size': <Parameter "size">}

As well as in instantiation:

Corn(10, 'yellow')

Producing:

yellow
10
{'color': <Parameter "color">, 'size': <Parameter "size">}

Note how this handles using *args, **kwargs in Corn's __init__ parameters.


Also, note the naming difference between arguments and parameters.

Comments

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.