is there any principle when writing python function

Steven D'Aprano steve+comp.lang.python at
Tue Aug 23 17:22:19 CEST 2011

smith jack wrote:

> i have heard that function invocation in python is expensive, 

It's expensive, but not *that* expensive. Compare:

[steve at sylar ~]$ python3.2 -m timeit 'x = "abc".upper()'
1000000 loops, best of 3: 0.31 usec per loop
[steve at sylar ~]$ python3.2 -m timeit -s 'def f():
return "abc".upper()' 'f()'
1000000 loops, best of 3: 0.53 usec per loop

So the function call is nearly as expensive as this (very simple!) sample
code. But in absolute terms, that's not very expensive at all. If we make
the code more expensive:

[steve at sylar ~]$ python3.2 -m timeit '("abc"*1000)[2:995].upper().lower()'
10000 loops, best of 3: 32.3 usec per loop
[steve at sylar ~]$ python3.2 -m timeit -s 'def f(): return ("abc"*1000
[2:995].upper().lower()' 'f()'
10000 loops, best of 3: 33.9 usec per loop

the function call overhead becomes trivial.

Cases where function call overhead is significant are rare. Not vanishingly
rare, but rare enough that you shouldn't worry about them.

> but make 
> lots of functions are a good design habit in many other languages, so
> is there any principle when writing python function?
> for example, how many lines should form a function?

About as long as a piece of string.

A more serious answer: it should be exactly as long as needed to do the
smallest amount of work that makes up one action, and no longer or shorter.

If you want to maximise the programmer's efficiency, a single function
should be short enough to keep the whole thing in your short-term memory at
once. This means it should consist of no more than seven, plus or minus
two, chunks of code. A chunk may be a single line, or a few lines that
together make up a unit, or if the lines are particularly complex, *less*
than a line.,_Plus_or_Minus_Two

(Don't be put off by the use of the term "magical" -- there's nothing
literally magical about this. It's just a side-effect of the way human
cognition works.)

Anything longer than 7±2 chunks, and you will find yourself having to scroll
backwards and forwards through the function, swapping information into your
short-term memory, in order to understand it.

Even 7±2 is probably excessive: I find that I'm most comfortable with
functions that perform 4±1 chunks of work. An example from one of my

    def find(self, prefix):
        """Find the item that matches prefix."""
        prefix = prefix.lower()  # Chunk #1
        menu = self._cleaned_menu  # Chunk #2
        for i,s in enumerate(menu, 1):  # Chunk #3
            if s.lower().startswith(prefix):
                return i
        return None  # Chunk #4

So that's three one-line chunks and one three-line chunk.


More information about the Python-list mailing list