55

I'm just learning python and confused when a "def" of a function ends?

I see code samples like:

def myfunc(a=4,b=6):
    sum = a + b
    return sum

myfunc()

I know it doesn't end because of the return (because I've seen if statements... if FOO than return BAR, else return FOOBAR). How does Python know this isn't a recursive function that calls itself? When the function runs does it just keep going through the program until it finds a return? That'd lead to some interesting errors.

Thanks

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Dan
  • 9,935
  • 15
  • 56
  • 66
  • 2
    It's a very good comment. Any introduction to Python mentions significant whitespace as one of the first, if not the first, things - it's one of the most distinctive Python features, after all. – Pavel Minaev Oct 15 '09 at 17:13
  • So far I was just using this cheat sheet: http://www.ibm.com/developerworks/library/l-cheatsheet3.html to just try and learn the syntax. If you have good tutorial suggestions I am open. – Dan Oct 15 '09 at 18:01
  • 1
    Google for any tutorial. They're probably slightly better. The cheat sheet says this "Blocks are indicated by indentation following a statement ending in a colon (:) as in..." so it isn't actively misleading you. – S.Lott Oct 15 '09 at 18:17
  • the best one would be dive into python – Bartosz Radaczyński Oct 15 '09 at 20:22
  • Think carefully about why there are spaces in front of `sum = a + b`. Did you try not using any spaces there? What happens if you try that? Does this give a hint? – Karl Knechtel Aug 13 '22 at 13:33
  • See also: [I'm getting an IndentationError. How do I fix it?](https://stackoverflow.com/questions/45621722) – Karl Knechtel Aug 13 '22 at 13:38

8 Answers8

73

In Python whitespace is significant. The function ends when the indentation becomes smaller (less).

def f():
    pass # first line
    pass # second line
pass # <-- less indentation, not part of function f.

Note that one-line functions can be written without indentation, on one line:

def f(): pass

And, then there is the use of semi-colons, but this is not recommended:

def f(): pass; pass

The three forms above show how the end of a function is defined syntactically. As for the semantics, in Python there are three ways to exit a function:

  • Using the return statement. This works the same as in any other imperative programming language you may know.

  • Using the yield statement. This means that the function is a generator. Explaining its semantics is beyond the scope of this answer. Have a look at Can somebody explain me the python yield statement?

  • By simply executing the last statement. If there are no more statements and the last statement is not a return statement, then the function exists as if the last statement were return None. That is to say, without an explicit return statement a function returns None. This function returns None:

    def f():
        pass
    

    And so does this one:

    def f():
        42
    
Community
  • 1
  • 1
Stephan202
  • 59,965
  • 13
  • 127
  • 133
  • OMG. This language is horrible! Hard to maintain. Why semicolons are NOT RECOMMENDED? How about types? When does it know that 52 is '4' and 52 is '52'? – TomeeNS Aug 18 '22 at 08:42
37

Python is white-space sensitive in regard to the indentation. Once the indentation level falls back to the level at which the function is defined, the function has ended.

fforw
  • 5,391
  • 1
  • 18
  • 17
  • 6
    Wow... was not expecting that. Never heard of indentation being used for anything but readability. Thanks! – Dan Oct 15 '09 at 16:39
10

To be precise, a block ends when it encounter a non-empty line indented at most the same level with the start. This non empty line is not part of that block For example, the following print ends two blocks at the same time:

def foo():
    if bar:
        print "bar"

print "baz" # ends the if and foo at the same time

The indentation level is less-than-or-equal to both the def and the if, hence it ends them both.

Lines with no statement, no matter the indentation, does not matter

def foo():
    print "The line below has no indentation"

    print "Still part of foo"

But the statement that marks the end of the block must be indented at the same level as any existing indentation. The following, then, is an error:

def foo():
    print "Still correct"
   print "Error because there is no block at this indentation"

Generally, if you're used to curly braces language, just indent the code like them and you'll be fine.

BTW, the "standard" way of indenting is with spaces only, but of course tab only is possible, but please don't mix them both.

RichN
  • 6,181
  • 3
  • 30
  • 38
5

Interestingly, if you're just typing at the python interactive interpreter, you have to follow a function with a blank line. This does not work:

def foo(x):
  return x+1
print "last"

although it is perfectly legal python syntax in a file. There are other syntactic differences when typing to the interpreter too, so beware.

GaryO
  • 5,873
  • 1
  • 36
  • 61
  • 1
    I think this is the sane way to write Python functions. "de-indenting" without a blank line seems like a recipe for trouble. – Andrew Wolfe Dec 19 '17 at 23:50
  • This is not a 'syntactic' difference with the interpreter so much as a practical one- the only reason for this is because otherwise there would be no way to write a multi-line function in the interpreter, and the interpreter makes it pretty clear that you're still writing part of the function definition with the leading `...`. In fact, [PEP8](https://www.python.org/dev/peps/pep-0008/#blank-lines) loosely outlines when you should and should not have blank lines after function definitions. – MoxieBall May 31 '18 at 17:44
2

white spaces matter. when block is finished, that's when the function definition is finished.

when function runs, it keeps going until it finishes, or until return or yield statement is encountered. If function finishes without encountering return or yield statements None is returned implicitly.

there is plenty more information in the tutorial.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
2

So its the indentation that matters. As other users here have pointed out to you, when the indentation level is at the same point as the def function declaration your function has ended. Keep in mind that you cannot mix tabs and spaces in Python. Most editors provide support for this.

Mohan Gulati
  • 28,219
  • 5
  • 22
  • 20
1

It uses indentation

 def func():
     funcbody
     if cond: 
         ifbody
     outofif

 outof_func 
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
0

In my opinion, it's better to explicitly mark the end of the function by comment

def func():
     # funcbody
     ## end of subroutine func ##

The point is that some subroutine is very long and is not convenient to scroll up the editor to check for which function is ended. In addition, if you use Sublime, you can right click -> Goto Definition and it will automatically jump to the subroutine declaration.

kstn
  • 537
  • 4
  • 14