Is there any downside to define a function that use one dictionary as an argument instead of several (+10) arguments? I tried to refactoring someone else's code and I found that there is alot of this pattern

def train(a, b, c, d, e, f, g, h, i, j, k): #Real code has longer name and around 10-20 arguments
    x = Dostuff()
    y = DoMoreStuff(b,c,d,e,f,g,h,x)
    z = DoMoreMoreStuff(a,b,d,e,g,h,j,y)

def DoMoreStuff(b,c,d,e,f,g,h):
    DoPrettyStuff(b,c,d,e,f,g,h) # The actually depth of function call is around 3-4 calls


I though that it would it be better to collect all of that a,b,c,d into one dictionary. I got this idea when I was reading about rail rack's middleware. 

env = {"a":1, "b", 2.......}
def train(env):
    x = Dostuff()
    y = DoMoreStuff(env.update({"x":x}))
    z = DoMoreMoreStuff(env.update({"y":y}))

def DoMoreStuff(env)
    DoPrettyStuff(env)


But I am not sure if there is any downside about this approach ? If it does help, every function here has a side-effect.

EDIT: For more clarification. I think most of my problem are about the propagation of variables. The call pattern has very deep and wide hierarchy. Any further suggestion about this one ?

def main(a,b,c,d,e,f,g,h,i,j,k,l,m....z):
    Do(...)
    #maybe other function()

def Do(a,b,c,d,e,f,g,h,i,j,k,l):
    Do1(d,e,f,g,h,i,j,k,l)

def Do1(d,e,f,g,h,i,j,k,l)
    Do2(f,g,h,i,j,k,l)

def Do2(f,g,h,i,j,k,l)
    Do3(f,g,h,i)
    Do4(j,k,l)


EDIT 2:  Well, my intention is that I want the code more easier to read and followed. Performance in python code does not matter much since the program spend most of the time on SVM and machine learning stuff. If anyone interest and don't mind a very dirty code that I still working on it. Here is the real code https://github.com/yumyai/TEES/tree/30b3aeaab011e30dcdc3c1151062697861ddcae1  

The code start with train.py (training model), classify.py (classify using model). In this case I'll use train.py as an example.
https://github.com/yumyai/TEES/blob/30b3aeaab011e30dcdc3c1151062697861ddcae1/train.py: line 136 where it start to call everything under it and pass a gigantic arguments to. These arguments are pass down to https://github.com/yumyai/TEES/blob/30b3aeaab011e30dcdc3c1151062697861ddcae1/Detectors/EventDetector.py: line 49. And then EventDetector pass these argument to it members (line 24-28).

Some argument is reused throughout the code, for example, def train(.......exampleStyles). exampleStyles is passed around to several member that is called by train.
Well, the answer depends on the meaning of the variables. If they are related (and they should be, since the same functions uses them!), then it's a good idea to group them in a dictionary since it makes the code more readable.

However, even if it makes sense to group all variables into a dict, your env.update() solution is not satisfying because it is unlikely that x and y really belong to env. What have you gained here? Function definitions may be shortened, but you only moved the problem to make it less visible. The next developer will be very surprised to see that you simply replaced function arguments by a dict without thinking about readability. This does not respect the Principle of least astonishment and probably others too.

You should try to group variables that really belong together, make use of *args and **kwargs whenever it makes sense, and otherwise split/reorganize functions that take too much unrelated arguments: they probably break the Single responsibility principe anyway.

Now, be careful when refactoring such functions, make sure you really understand them, and write unit tests or integration tests before changing them to make sure you don't make the code worse than before.