There are some cases where 200-line methods are perfectly acceptable, when breaking the logic into smaller functions only complicates the understanding and development of the algorithm. Not everything can be broken into multiple elegant 10-line functions without obfuscating the purpose or control flow.
One thing I've occasionally done to tame large functions is this:
def frobWidget(widget):
def frobCog(cog):
## stuff involving both cog and widget
## stuff involving widget
frobbedCogs = [frobCog(cog) for cog in widget]
## more stuff involving widget and frobbedCogs
If frobCog were broken out into a separate function, then it would have to take widget as an argument, and if frobCog is never actually called from anywhere other than within frobWidget, then such separation makes the code harder to understand. Keeping the definition internal lets me take advantage of lexical scope; I can refer to widget within the definition of frobCog.
In the example you showed I'd probably do the same, true, but I think there is no evil in passing widget as an argument.
In general, there's nothing wrong with functions that take everything they use as arguments. This is kind of functional programming (or a good part of it): every function is as independent as possible, which makes them easier to debug, easier to understand, and safer in terms of bugs. Functions that deal with data from outer scopes risk being less readable and less reliable.
Formally speaking, every line and every block (if, while...) can be moved to a separate function. Provided that functions are given fairly descriptive names, it is always possible to go as far as you wish in splitting your functions into smaller ones. I don't see any problem with that except reading/understanding, of course, which depends on your "target audience" so to say.
If you have a good sense of code aesthetics, you can make your code look like pseudo-code, which every decent coder is supposed to understand. So your quicksort may look almost like:
function quicksort(array)
var list less, greater
if length(array) ≤ 1
return array
select and remove a pivot value pivot from array
for each x in array
if x ≤ pivot then append x to less
else append x to greater
return concatenate(quicksort(less), pivot, quicksort(greater))
or it may be a 50-liner with no sub-routines. It's a matter of choice, really.