1

Is there a cleaner way to get the defaults of a method than using the inspect module? I'd like to do this:

class C(object):
    def __init__(self,Type='generic',X=5,Y=500):
        defaults=getDefaults() #not sure about this line
        typeDefaults_X={'short':'1','long':'10'}
        typeDefaults_Y={'large':2000,'small':100}
        if X == defaults['X']: 
            X = typeDefaults_X.get(Type, defaults['X'])
        if Y == defaults['Y']: 
            Y = typeDefaults_Y.get(Type, defaults['Y'])

I know that I could do this by:

defaults=dict(zip(inspect.getargspec(C.__init__).args[1:],inspect.getargspec(C.__init__).defaults))

but it seems so terribly un-pythonic.

4
  • What is the point? What are you trying to do? Commented Apr 19, 2011 at 1:12
  • 1
    You will want == instead of is; for example note that 100000+1 is 100000+1 is False, but 100+1 is 100+1 is True. Commented Apr 19, 2011 at 1:32
  • What your code says is "if we don't input anything for argN, set it to lookupTable[typeString]; if that fails, set it to the default value". This interface as you have illustrated unfortunately doesn't make sense, since you only have 1 typeString parameter, but your variables seem to all depend on it, and they all have separate lookup tables with different keys. What are you trying to do? Commented Apr 19, 2011 at 1:35
  • Basically I'm trying to change the defaults for all args depending on the Type parameter. Commented Apr 19, 2011 at 18:02

2 Answers 2

1

It's not really clear to me what you are trying to do. But in the method, variable already has the specified default value. But it seems to me that you would be better off not using formal default arguments in this case.

class C(object):

    def __init__(self, Type='generic', X=None, Y=None):
        X = X or 5
        Y = Y or 500
        self.X, self.Y = {
            "generic": (X, Y),
            "short": (1, Y),
            "long": (10, Y),
            "large": (X, 2000),
            "small": (X, 100),
        }[Type]

    def __str__(self):
        return "X={0} Y={1}".format(self.X, self.Y)


print(C())
print(C('short'))
print(C('long'))
print(C('large'))
print(C('small'))
print(C('small', 10))
print(C('small', 20, 20))

Is clearer I think, but even this can be a little hard to follow. You might rethink your interface.

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

2 Comments

Thanks, I think this could work. Ideally I'd like to keep the formal default arguments here (with values). I'm rethinking.... maybe child classes?
@Adam Exactly what I was thinking. :-) Generally, if you see methods that change behavior base on some flag it should really be refactored into subclasses.
0

It's actually slightly worse than you think. Python distinguishes between a positional arg with defaults and a keyword-only arg. Your code fail not only in cases where you don't have a default as your second or third arguments, but also if you have a variable-length *args keyword. You should also use inspect.getfullargspec.

However, according to help(inspect.getfullargspec), the spec.defaults are always the last elements of the spec.args. Thus you can do this:

import inspect
def getDefaults(func):
    spec = inspect.getfullargspec(func)
    numDefaults = len(spec.defaults)
    return dict(zip(spec.args[-numDefaults:], spec.defaults), **spec.kwonlydefaults)

Basically, this is exactly what you did, but a bit more general.

There is no better way. (Well you could use func.__defaults, func.__kwdefaults__, func.__code__.co_*, but those are really hackish and seem to kind of internals. Inspect is the right way.)

1 Comment

addendum: this seems to actually be the definition of 'pythonic': there is one and only one way to do it; this isn't to say it couldn't be massively improved and still be 'pythonic'

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.