I was looking how to pass all arguments from un function to another.

My scenario was :

I want to do something linke GOF design pattern: chain of responsibility. Basically you have a list of functions, and you want to iterate over them, and execute one after another, passing the result among them. Further infromation on this link : https://www.toptal.com/python/python-design-patterns

On a queck google search I found the usage of locals() : https://stackoverflow.com/questions/3136915/passing-all-arguments-of-a-function-to-another-function?rq=1&utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

With locals() you can access to local namespace, it will give it to you in a key:value dictionary.

I opened a python console and gave it a try:


class Gon:
... name = "Gonzalo"
... 
obj = Gon()
obj.name
'Gonzalo'
def foo1(obj):
... print(obj.name)
... foo2(**locals())
... 
 def foo2(*args,**kwargs):
... import pdb;pdb.set_trace()
... 
 foo1(obj)
Gonzalo
(3)foo2()
(Pdb) a
args = ()
kwargs = {'obj': __main__.Gon instance at 0x7fe503bb5ef0;}
(Pdb) gon = kwargs.get('obj')
(Pdb) gon.name
'Gonzalo'

 NICE! … that is enough? , maybe for some situations it is…..

But what happens if you want some recursion? or you have self in your function, or requests? Or you want to maintain a global state? ..

OOPS! Let’s see..

Consider this scenario.


def create(self,request):

    code = request.get('code')
    dict = {'block_code':code}
    _park(**dict)

def _park(*args,**kwargs):
    import pdb;pdb.set_trace()
    new_variable = "pepe"
    _other_foo(**locals())

def _other_foo(*args,**kwargs):
    return 0

Someone will call create function, for example a we service (that’s why the request into the parameters)

When debugging


(Pdb) pp(kwargs)

{'block_code': '0101'}

(Pdb) n (we go next step, new variable="pepe")

(Pdb) s(we go next step, into _other_foo execution)

(Pdb) pp(kwargs)

{'args': (),
 'block_code':'0101',

new_variable = "pepe"
 'kwargs': {'block_code': '0101'},

 'pprint': function pprint at 0x7f975e2c41e0,
}

So as you can see, as it expected, it passes all local variables, including self, to the function.

If we want to maintain some state among executions, this is probably not what you want!

Locals() is a copy of local namespace, and it is READ ONLY. So if you want to change some value and pass it to next function, you better use **kwargs.

Another reason, is that if you have 100 calls.. you will have a 100 leve depth dictionary, with all replicated information.

Now assume, we have this code instead


def _park(*args,**kwargs):

   new_variable = "pepe"
   _otra_funcion(**kwargs)


When executing, and debugging


(Pdb) pp(kwargs)

{'block_code': '0101'}

(Pdb)n

(Pdb)s

(Pdb) pp(kwargs)

{'block_code': '0101',

new_variable='pepe'}

So as you can see, we only maintain one referene to the original dictionary.  We also prevent of passing aroung replicated data.

BE CAREFUL: you can change values of original data , probably is what you want.

Nice coding!

Gonzalo.