0

I searched quite a bit for this, so please forgive if I missed something.

I generally desire that methods in my system have only explicit named arguments (other than self of course), like so:

# want an explicit parameter signature
def method_1(self, *, x = None, y = None):
    . . .
    # and here i want to pass x and/or y if they are not None
    possible_args = { }
    if x is not None:
        possible_args['x'] = x
    if y is not None:
        possible_args['y'] = y

    self.method_2(**possible_args)

# want an explicit parameter signature
def method_2(self, *, x = 1, y = None):
    . . .

unfortunately, the values of x and/or y do not get mapped into the named args in method_2, but if i do this instead at the end of method_1:

self.method_2(x = x, y = y)

then the default values of x and y from method_1 override the default values as expressed in the method_2 signature.

what I want is a way, without vaguifying method signatures by accepting an entirely open and unspecified **kwargs, to map whatever might be specified in the call dict into explicit named parameters and not override the defaults for other args that are not in the passed dict.

is this possible?

this is for a system of hundreds of classes, and their interfaces need to be very well specified, else this way lies madness. that is why i do not want to be passing **kwargs around except in a very controlled manner, and I also want to take advantage of named arguments having defaults specified in the method signature. otherwise, i could deal with defaults within the method body, of course:

if x is None:
    x = 5

that's just not as nice...

Bruce
  • 25
  • 3
  • Can you provide an [MCVE] that demonstrates the incorrect behavior? I get the gist of what you are asking, but am not entirely certain I understand exactly what you want. – Steve Cohen May 04 '16 at 22:45
  • @steve: hmmm, are you saying such mapping _should_ be taking place? i'll try to make a better and executable example. until then, assume i've botched this somehow. will get back... thanks. – Bruce May 04 '16 at 23:02
  • sigh. it seems I am completely wrong here. the behavior i saw was my own doing. in my own very meager defense, i did ask our in-house very knowledgeable python person this same question, and he said it would not work where a passed **kwargs would map its arguments into a set of named args in the called method's signature, but it appears, as I try to test this further, that it is doing exactly that. i'm so happy about this, i'll get over being down-voted. my abject apologies for wasting your time. if revenge is what you want now, just be aware that i wasted a lot more of my own time!! :- – Bruce May 04 '16 at 23:21
  • how does a question get withdrawn so as not to waste anyone else's time? – Bruce May 04 '16 at 23:22
  • 1
    At least there is now a decent example for the next guy. I am not sure this should go away. Also - beware your "in-house very knowledgeable python person". I should also mention that using magic **kwargs expansion can be, err... confusing for the next person. And more often than not, I am my own next person. – Steve Cohen May 04 '16 at 23:25
  • thanks for your help (and moreso, understanding. ha!) – Bruce May 05 '16 at 20:03

1 Answers1

1

So I gave it a whirl, because I was lost as to what the problem was. I am still lost, but at least now I can show you an MCVE for it:

#! /usr/bin/env python3

'''
A quick **kwargs demo
'''


def method_1(*, x_val=None, y_val=None):
    '''
    A demonstration with kwargs, that calls another with **kwargs.
    '''

    possible_args = {}
    if x_val is not None:
        possible_args['x_val'] = x_val
    if y_val is not None:
        possible_args['y_val'] = y_val
    method_2(**possible_args)


def method_2(*, x_val=1, y_val='y_from_2'):
    '''
    Print things for the demo.
    '''
    print('x_val = ', x_val, ', y_val = ', y_val)

method_1(x_val=17, y_val=7)
method_1(x_val=13)
method_1(y_val=5)
method_1()

Produces the output:

x_val =  17 , y_val =  7
x_val =  13 , y_val =  y_from_2
x_val =  1 , y_val =  5
x_val =  1 , y_val =  y_from_2

Which is exactly what one should expect.

Steve Cohen
  • 722
  • 4
  • 6
  • this shows exactly the behavior i wanted but did not think i was seeing. thanks very much. – Bruce May 05 '16 at 22:55