7

What I want to accomplish:

dct = {'foo':0, 'bar':1, 'baz':2}
def func(**dct):
    pass
#function signature is now func(foo=0, bar=1, baz=2)

However, the ** syntax is obviously clashing here between expanding a dict (what I want to do) and declaring a parameter that holds the keyword arguments (what I don't want to do).

Is this possible?

Lanaru
  • 9,421
  • 7
  • 38
  • 64

3 Answers3

7

Based on my interpretation of your requirements -- you want to dynamically define a function with a signature that matches the content of adict provided at runtime -- there are two issues here which makes it impractical.

  1. If the arguments are defined at run-time, how can your function reference the variables? Are you planning to build the function body at run-time as well?
  2. dicts are unordered, so you cannot reliably use them to define positional arguments

I suspect this is an XY problem. If you can explain what you're trying to achieve then perhaps we can be of better help.

However, assuming you're trying to assign default keyword arguments using a dict then one way to achieve this would be to use decorators. For example:

def defaultArgs(default_kw):
    "decorator to assign default kwargs"
    def wrap(f):
        def wrapped_f(**kwargs):
            kw = {}
            kw.update(default_kw)  # apply defaults
            kw.update(kwargs)  # apply from input args
            f(**kw)  # run actual function with updated kwargs
        return wrapped_f
    return wrap

You can then use this decorator to assign default keyword arguments to a function that expects only keyword arguments:

defaults = {'foo':0, 'bar':1, 'baz':2}

@defaultArgs(defaults)
def func(**kwargs):
    print kwargs  # args accessible via the kwargs dict

Results:

func()  # prints {'baz': 2, 'foo': 0, 'bar': 1}
func(foo=2)  # prints {'baz': 2, 'foo': 2, 'bar': 1}

params = {'bar':1000, 'hello':'world'}
func(**params)  # prints {'baz': 2, 'foo': 0, 'bar': 1000, 'hello': 'world'}

Note that you will not be able to use positional arguments:

func(1, 2, 3)   # raises TypeError
Community
  • 1
  • 1
Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
  • Thanks for your answer, it helped me accomplish what I want to do. I think it was, as you've stated, an XY problem; I was simply going about things the wrong way. It honestly kind of surprised me that I put myself into this predicament, since the last time I remember something like this happening was when I was a beginner at programming and learning Java for the first time, then being incensed that there wasn't a goto statement (when there were other, better solutions to my problem). – Lanaru Aug 14 '12 at 16:36
  • 1
    Glad you found a solution! We've all been in that position and sometimes all it takes is a gentle reminder to take a step back and reformulate the problem. – Shawn Chin Aug 14 '12 at 16:49
0

what you want i believe is eval() link

an answer i gave on a similar question: https://stackoverflow.com/a/11865190/1561176

Community
  • 1
  • 1
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
0

I'm really not sure what you plan on accomplishing here. The following works (sort of):

def func(**dct):
    pass

dct = {'foo':0, 'bar':1, 'baz':2}
func(**dct)

How do you plan on using foo, bar or baz in the function if they're created dynamically? If you give some more details on what you're actually trying to accomplish, we might be able to be a little more helpful.

mgilson
  • 300,191
  • 65
  • 633
  • 696