Basics Intermediate Advanced
aialgorithmsapibest-practicescareercommunitydatabasesdata-sciencedata-structuresdata-vizdevopsdjangodockereditorsflaskfront-endgamedevguimachine-learningnewsnumpyprojectspythonstdlibtestingtoolsweb-devweb-scraping
- Getting Started With Python Functions
- Understanding the Python return Statement
- Returning vs Printing
- Returning Multiple Values
- Using the Python return Statement: Best Practices
- Returning Functions: Closures
- Taking and Returning Functions: Decorators
- Returning User-Defined Objects: The Factory Pattern
- Using return in try … finally Blocks
- Using return in Generator Functions
- FAQs
Recommended Course

Using the Python return Statement Effectively
1h 30m · 22 lessons

The Python return Statement: Usage and Best Practices
Table of Contents
- Getting Started With Python Functions
- Understanding the Python return Statement
- Returning vs Printing
- Returning Multiple Values
- Using the Python return Statement: Best Practices
- Returning Functions: Closures
- Taking and Returning Functions: Decorators
- Returning User-Defined Objects: The Factory Pattern
- Using return in try … finally Blocks
- Using return in Generator Functions
- FAQs
Recommended Course
The Pythonreturn statement is a special statement that you can use inside afunction ormethod to send the function’s result back to the caller. Areturn statement consists of thereturn keyword followed by an optionalreturn value. The return value of a Python function can be any Python object, and you can use them to perform further computation in your programs.
Using thereturn statement effectively is a core skill if you want to code custom functions that arePythonic and robust.
In this tutorial, you’ll learn that:
- You use
returnto send objects from your functions back to the caller code. - You can use
returnto return one single value or multiple values separated by commas. - You should try to keep your code readable and maintainable by avoiding complex
returnstatements.
With this knowledge, you’ll be able to write more readable, maintainable, and concise functions in Python. If you’re totally new to Python functions, then you can check outDefining Your Own Python Function before diving into this tutorial.
Free Bonus:5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.
Take the Quiz: Test your knowledge with our interactive “The Python return Statement” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
The Python return StatementIn this quiz, you can practice your understanding of how to use the Python return statement when writing functions. Additionally, you'll cover some good programming practices related to the use of return. With this knowledge, you'll be able to write readable, robust, and maintainable functions in Python.
Getting Started With Python Functions
Most programming languages allow you to assign a name to a code block that performs a concrete computation. These named code blocks can be reused quickly because you can use their name to call them from different places in your code.
Programmers call these named code blockssubroutines,routines,procedures, orfunctions depending on the language they use. In some languages, there’s a clear difference between a routine or procedure and a function.
Sometimes that difference is so strong that you need to use a specific keyword to define a procedure or subroutine and another keyword to define a function. For example theVisual Basic programming language usesSub andFunction to differentiate between the two.
In general, aprocedure is a named code block that performs a set of actions without computing a final value or result. On the other hand, afunction is a named code block that performs some actions with the purpose of computing a final value or result, which is then sent back to the caller code. Both procedures and functions can act upon a set ofinput values, commonly known asarguments.
In Python, these kinds of named code blocks are known asfunctions because they always send a value back to the caller. The Python documentation defines a function as follows:
A series of statements which returns some value to a caller. It can also be passed zero or morearguments which may be used in the execution of the body. (Source)
Even though the official documentation states that a function “returns some value to the caller,” you’ll soon see that functions can return any Python object to the caller code.
In general, a functiontakes arguments (if any),performs some operations, andreturns a value (or object). The value that a function returns to the caller is generally known as the function’sreturn value. All Python functions have a return value, either explicit or implicit. You’ll cover the difference between explicit and implicit return values later in this tutorial.
To write a Python function, you need aheader that starts with thedef keyword, followed by the name of the function, an optional list of comma-separated arguments inside a required pair of parentheses, and a final colon.
The second component of a function is itscode block, orbody. Python defines code blocks usingindentation instead of brackets,begin andend keywords, and so on. So, to define a function in Python you can use the following syntax:
deffunction_name(arg1,arg2,...,argN):# Function's code goes here...passWhen you’re coding a Python function, you need to define a header with thedef keyword, the name of the function, and a list of arguments in parentheses. Note that the list of arguments is optional, but the parentheses are syntactically required. Then you need to define the function’s code block, which will begin one level of indentation to the right.
In the above example, you use apass statement. This kind of statement is useful when you need a placeholder statement in your code to make it syntactically correct, but you don’t need to perform any action.pass statements are also known as thenull operation because they don’t perform any action.
Note: The full syntax to define functions and their arguments is beyond the scope of this tutorial. For an in-depth resource on this topic, check outDefining Your Own Python Function.
To use a function, you need to call it. A function call consists of the function’s name followed by the function’s arguments in parentheses:
function_name(arg1,arg2,...,argN)You’ll need to pass arguments to a function call only if the function requires them. The parentheses, on the other hand, are always required in a function call. If you forget them, then you won’t be calling the function but referencing it as a function object.
To make your functions return a value, you need to use thePythonreturn statement. That’s what you’ll cover from this point on.
Understanding the Pythonreturn Statement
ThePythonreturn statement is a special statement that you can use inside a function ormethod to send the function’s result back to the caller. Areturn statement consists of thereturn keyword followed by an optionalreturn value.
The return value of a Python function can be any Python object. Everything in Python is an object. So, your functions can return numeric values (int,float, andcomplex values), collections and sequences of objects (list,tuple,dictionary, orset objects), user-defined objects, classes, functions, and evenmodules or packages.
You can omit the return value of a function and use a barereturn without a return value. You can also omit the entirereturn statement. In both cases, the return value will beNone.
In the next two sections, you’ll cover the basics of how thereturn statement works and how you can use it to return the function’s result back to the caller code.
Explicitreturn Statements
Anexplicitreturn statement immediately terminates a function execution and sends the return value back to the caller code. To add an explicitreturn statement to a Python function, you need to usereturn followed by an optional return value:
>>>defreturn_42():...return42# An explicit return statement...>>>return_42()# The caller code gets 4242When you definereturn_42(), you add an explicitreturn statement (return 42) at the end of the function’s code block.42 is the explicit return value ofreturn_42(). This means that any time you callreturn_42(), the function will send42 back to the caller.
Note: You can use explicitreturn statements with or without a return value. If you build areturn statement without specifying a return value, then you’ll be implicitly returningNone.
If you define a function with an explicitreturn statement that has an explicit return value, then you can use that return value in any expression:
>>>num=return_42()>>>num42>>>return_42()*284>>>return_42()+547Sincereturn_42() returns a numeric value, you can use that value in a math expression or any other kind of expression in which the value has a logical or coherent meaning. This is how a caller code can take advantage of a function’s return value.
Note that you can use areturn statement only inside a function or method definition. If you use it anywhere else, then you’ll get aSyntaxError:
>>>return42 File"<stdin>", line1SyntaxError:'return' outside functionWhen you usereturn outside a function or method, you get aSyntaxError telling you that the statement can’t be used outside a function.
Note:Regular methods, class methods, and static methods are just functions within the context ofPython classes. So, all thereturn statement concepts that you’ll cover apply to them as well.
You can use any Python object as a return value. Since everything in Python is an object, you can returnstrings, lists, tuples, dictionaries, functions,classes, instances, user-defined objects, and even modules or packages.
For example, say you need to write a function that takes a list of integers and returns a list containing only the even numbers in the original list. Here’s a way of coding this function:
>>>defget_even(numbers):...even_nums=[numfornuminnumbersifnotnum%2]...returneven_nums...>>>get_even([1,2,3,4,5,6])[2, 4, 6]get_even() uses alist comprehension to create a list that filters out the odd numbers in the originalnumbers. Then the function returns the resulting list, which contains only even numbers.
A common practice is to use the result of anexpression as a return value in areturn statement. To apply this idea, you can rewriteget_even() as follows:
>>>defget_even(numbers):...return[numfornuminnumbersifnotnum%2]...>>>get_even([1,2,3,4,5,6])[2, 4, 6]The list comprehension gets evaluated and then the function returns with the resulting list. Note that you can only useexpressions in areturn statement. Expressions are different fromstatements likeconditionals orloops.
Note: Even thoughlist comprehensions are built usingfor and (optionally)if keywords, they’re considered expressions rather than statements. That’s why you can use them in areturn statement.
For a further example, say you need to calculate the mean of a sample of numeric values. To do that, you need to divide the sum of the values by the number of values. Here’s an example that uses the built-in functionssum() andlen():
>>>defmean(sample):...returnsum(sample)/len(sample)...>>>mean([1,2,3,4])2.5Inmean(), you don’t use a localvariable to store the result of the calculation. Instead, you use the expression directly as a return value. Python first evaluates the expressionsum(sample) / len(sample) and then returns the result of the evaluation, which in this case is the value2.5.
Implicitreturn Statements
A Python function will always have a return value. There is no notion of procedure or routine in Python. So, if you don’t explicitly use a return value in areturn statement, or if you totally omit thereturn statement, then Python will implicitly return a default value for you. That default return value will always beNone.
Say you’re writing a function that adds1 to a numberx, but you forget to supply areturn statement. In this case, you’ll get animplicitreturn statement that usesNone as a return value:
>>>defadd_one(x):...# No return statement at all...result=x+1...>>>value=add_one(5)>>>value>>>print(value)NoneIf you don’t supply an explicitreturn statement with an explicit return value, then Python will supply an implicitreturn statement usingNone as a return value. In the above example,add_one() adds1 tox and stores the value inresult but it doesn’t returnresult. That’s why you getvalue = None instead ofvalue = 6. To fix the problem, you need to eitherreturn result or directlyreturn x + 1.
An example of a function that returnsNone isprint(). The goal of this function is to print objects to a text stream file, which is normally the standard output (your screen). So, this function doesn’t need an explicitreturn statement because it doesn’t return anything useful or meaningful:
>>>return_value=print("Hello, World")Hello, World>>>print(return_value)NoneThe call toprint() printsHello, World to the screen. Since this is the purpose ofprint(), the function doesn’t need to return anything useful, so you getNone as a return value.
Note: ThePython interpreter doesn’t displayNone. So, to show a return value ofNone in aninteractive session, you need to explicitly useprint().
Regardless of how long and complex your functions are, any function without an explicitreturn statement, or one with areturn statement without a return value, will returnNone.
Returning vs Printing
If you’re working in an interactive session, then you might think that printing a value and returning a value are equivalent operations. Consider the following two functions and their output:
>>>defprint_greeting():...print("Hello, World")...>>>print_greeting()Hello, World>>>defreturn_greeting():...return"Hello, World"...>>>return_greeting()'Hello, World'Both functions seem to do the same thing. In both cases, you seeHello, World printed on your screen. There’s only a subtle visible difference—the single quotation marks in the second example. But take a look at what happens if you return another data type, say anint object:
>>>defprint_42():...print(42)...>>>print_42()42>>>defreturn_42():...return42...>>>return_42()42There’s no visible difference now. In both cases, you can see42 on your screen. That behavior can be confusing if you’re just starting with Python. You might think that returning and printing a value are equivalent actions.
Now, suppose you’re getting deeper into Python and you’re starting to write your first script. You open a text editor and type the following code:
1defadd(a,b): 2result=a+b 3returnresult 4 5add(2,2)add() takes two numbers, adds them, and returns the result. Online 5, you calladd() to sum2 plus2. Since you’re still learning the difference between returning and printing a value, you might expect your script to print4 to the screen. However, that’s not what happens, and you get nothing on your screen.
Try it out by yourself. Save your script to a file calledadding.py andrun it from your command line as follows:
$python3adding.pyIf you runadding.py from your command line, then you won’t see any result on your screen. That’s because when you run a script, the return values of the functions that you call in the script don’t get printed to the screen like they do in an interactive session.
If you want that your script to show the result of callingadd() on your screen, then you need to explicitly callprint(). Check out the following update ofadding.py:
1defadd(a,b): 2result=a+b 3returnresult 4 5print(add(2,2))Now, when you runadding.py, you’ll see the number4 on your screen.
So, if you’re working in an interactive session, then Python will show the result of any function call directly to your screen. But if you’re writing a script and you want to see a function’s return value, then you need to explicitly useprint().
Returning Multiple Values
You can use areturn statement to return multiple values from a function. To do that, you just need to supply several return values separated by commas.
For example, suppose you need to write a function that takes a sample of numeric data and returns a summary of statistical measures. To code that function, you can use the Python standard modulestatistics, which provides several functions for calculating mathematical statistics of numeric data.
Here’s a possible implementation of your function:
importstatisticsasstdefdescribe(sample):returnst.mean(sample),st.median(sample),st.mode(sample)Indescribe(), you take advantage of Python’s ability to return multiple values in a singlereturn statement by returning the mean, median, and mode of the sample at the same time. Note that, to return multiple values, you just need to write them in a comma-separated list in the order you want them returned.
Note: If your functions needs several different return types, then you’re dealing with a more complex scenario. In this case, you can get some help fromHow to Use Type Hints for Multiple Return Types in Python.
Once you’ve codeddescribe(), you can take advantage of a powerful Python feature known asiterable unpacking to unpack the three measures into three separatedvariables, or you can just store everything in one variable:
>>>sample=[10,2,4,7,9,3,9,8,6,7]>>>mean,median,mode=describe(sample)>>>mean6.5>>>median7.0>>>mode7>>>desc=describe(sample)>>>desc(6.5, 7.0, 7)>>>type(desc)<class 'tuple'>Here, you unpack the three return values ofdescribe() into the variablesmean,median, andmode. Note that in the last example, you store all the values in a single variable,desc, which turns out to be a Pythontuple.
Note: You can build a Pythontuple by justassigning several comma-separated values to a single variable. There’s no need to use parentheses to create atuple. That’s why multiple return values are packed in atuple.
The built-in functiondivmod() is also an example of a function that returns multiple values. The function takes two (non-complex) numbers as arguments and returns two numbers, the quotient of the two input values and the remainder of the division:
>>>divmod(15,3)(5, 0)>>>divmod(8,3)(2, 2)The call todivmod() returns a tuple containing the quotient and remainder that result from dividing the two non-complex numbers provided as arguments. This is an example of a function with multiple return values.
Using the Pythonreturn Statement: Best Practices
So far, you’ve covered the basics of how the Pythonreturn statement works. You now know how to write functions that return one or multiple values to the caller. Additionally, you’ve learned that if you don’t add an explicitreturn statement with an explicit return value to a given function, then Python will add it for you. That value will beNone.
In this section, you’ll cover several examples that will guide you through a set of good programming practices for effectively using thereturn statement. These practices will help you to write more readable, maintainable, robust, and efficient functions in Python.
ReturningNone Explicitly
Some programmers rely on the implicitreturn statement that Python adds to any function without an explicit one. This can be confusing for developers who come from other programming languages in which a function without a return value is called aprocedure.
There are situations in which you can add an explicitreturn None to your functions. In other situations, however, you can rely on Python’s default behavior:
If your function performs actions but doesn’t have a clear and useful
returnvalue, then you can omit returningNonebecause doing that would just be superfluous and confusing. You can also use a barereturnwithout a return value just to make clear your intention of returning from the function.If your function has multiple
returnstatements and returningNoneis a valid option, then you should consider the explicit use ofreturn Noneinstead of relying on the Python’s default behavior.
These practices can improve the readability and maintainability of your code by explicitly communicating your intent.
When it comes to returningNone, you can use one of three possible approaches:
- Omit the
returnstatement and rely on the default behavior of returningNone. - Use a bare
returnwithout a return value, which also returnsNone. - Return
Noneexplicitly.
Here’s how this works in practice:
>>>defomit_return_stmt():...# Omit the return statement...pass...>>>print(omit_return_stmt())None>>>defbare_return():...# Use a bare return...return...>>>print(bare_return())None>>>defreturn_none_explicitly():...# Return None explicitly...returnNone...>>>print(return_none_explicitly())NoneWhether or not to returnNone explicitly is a personal decision. However, you should consider that in some cases, an explicitreturn None can avoid maintainability problems. This is especially true for developers who come from other programming languages that don’t behave like Python does.
Remembering the Return Value
When writing custom functions, you might accidentally forget to return a value from a function. In this case, Python will returnNone for you. This can cause subtle bugs that can be difficult for a beginning Python developer tounderstand and debug.
You can avoid this problem by writing thereturn statement immediately after the header of the function. Then you can make a second pass to write the function’s body. Here’s a template that you can use when coding your Python functions:
deftemplate_func(args):result=0# Initialize the return value# Your code goes here...returnresult# Explicitly return the resultIf you get used to starting your functions like this, then chances are that you’ll no longer miss thereturn statement. With this approach, you can write the body of the function, test it, and rename the variables once you know that the function works.
This practice can increase your productivity and make your functions less error-prone. It can also save you a lot ofdebugging time.
Avoiding Complex Expressions
As you saw before, it’s a common practice to use the result of an expression as a return value in Python functions. If the expression that you’re using gets too complex, then this practice can lead to functions that are difficult to understand, debug, and maintain.
For example, if you’re doing a complex calculation, then it would be more readable to incrementally calculate the final result usingtemporary variables with meaningful names.
Consider the following function that calculates thevariance of a sample of numeric data:
>>>defvariance(data,ddof=0):...mean=sum(data)/len(data)...returnsum((x-mean)**2forxindata)/(len(data)-ddof)...>>>variance([3,4,7,5,6,2,9,4,1,3])5.24The expression that you use here is quite complex and difficult to understand. It’s also difficult to debug because you’re performing multiple operations in a single expression. To work around this particular problem, you can take advantage of an incremental development approach that improves the readability of the function.
Take a look at the following alternative implementation ofvariance():
>>>defvariance(data,ddof=0):...n=len(data)...mean=sum(data)/n...total_square_dev=sum((x-mean)**2forxindata)...returntotal_square_dev/(n-ddof)...>>>variance([3,4,7,5,6,2,9,4,1,3])5.24In this second implementation ofvariance(), you calculate the variance in several steps. Each step is represented by a temporary variable with a meaningful name.
Temporary variables liken,mean, andtotal_square_dev are often helpful when it comes to debugging your code. If, for example, something goes wrong with one of them, then you can callprint() to know what’s happening before thereturn statement runs.
In general, you should avoid using complex expressions in yourreturn statement. Instead, you can break your code into multiple steps and use temporary variables for each step. Using temporary variables can make your code easier to debug, understand, and maintain.
Returning Values vs Modifying Globals
Functions that don’t have an explicitreturn statement with a meaningful return value often preform actions that haveside effects. Aside effect can be, for example, printing something to the screen, modifying aglobal variable, updating the state of an object,writing some text to a file, and so on.
Modifying global variables is generally considered a bad programming practice. Just like programs with complex expressions, programs that modify global variables can be difficult to debug, understand, and maintain.
When you modify a global variable, you’re potentially affecting all the functions, classes, objects, and any other parts of your programs that rely on that global variable.
To understand a program that modifies global variables, you need to be aware of all the parts of the program that can see, access, and change those variables. So, good practice recommends writingself-contained functions that take some arguments and return a useful value (or values) without causing any side effect on global variables.
Additionally, functions with an explicitreturn statement that return a meaningful value are easier totest than functions that modify or update global variables.
The following example show a function that changes a global variable. The function uses theglobal statement, which is also considered a bad programming practice in Python:
>>>counter=0>>>defincrement():...globalcounter...counter+=1...>>>increment()>>>counter1In this example, you first create a global variable,counter, with an initial value of0. Insideincrement(), you use aglobal statement to tell the function that you want to modify a global variable. The last statement incrementscounter by1.
The result of callingincrement() will depend on the initial value ofcounter. Different initial values forcounter will generate different results, so the function’s result can’t be controlled by the function itself.
To avoid this kind of behavior, you can write a self-containedincrement() that takes arguments and returns a coherent value that depends only on the input arguments:
>>>counter=0>>>defincrement(var):...returnvar+1...>>>increment(counter)1>>>counter0>>># Explicitly assign a new value to counter>>>counter=increment(counter)>>>counter1Now the result of callingincrement() depends only on the input arguments rather than on the initial value ofcounter. This makes the function more robust and easier to test.
Note: For a better understanding of how to test your Python code, check outTest-Driven Development With PyTest.
If you’d like a deeper dive into using global variables in functions, thenUsing and Creating Global Variables in Your Python Functions is for you.
Additionally, when you need to updatecounter, you can do so explicitly with a call toincrement(). This way, you’ll have more control over what’s happening withcounter throughout your code.
In general, it’s a good practice to avoid functions that modify global variables. If possible, try to writeself-contained functions with an explicitreturn statement that returns a coherent and meaningful value.
Usingreturn With Conditionals
Python functions are not restricted to having a singlereturn statement. If a given function has more than onereturn statement, then the first one encountered will determine the end of the function’s execution and also its return value.
A common way of writing functions with multiplereturn statements is to useconditional statements that allow you to provide differentreturn statements depending on the result of evaluating some conditions.
Suppose you need to code a function that takes a number and returns itsabsolute value. If the number is greater than0, then you’ll return the same number. If the number is less than0, then you’ll return its opposite, or non-negative value.
Here’s a possible implementation for this function:
>>>defmy_abs(number):...ifnumber>0:...returnnumber...elifnumber<0:...return-number...>>>my_abs(-15)15>>>my_abs(15)15my_abs() has two explicitreturn statements, each of them wrapped in its ownif statement. It also has an implicitreturn statement. Ifnumber happens to be0, then neither condition is true, and the function ends without hitting any explicitreturn statement. When this happens, you automatically getNone.
Take a look at the following call tomy_abs() using0 as an argument:
>>>print(my_abs(0))NoneWhen you callmy_abs() using0 as an argument, you getNone as a result. That’s because the flow of execution gets to the end of the function without reaching any explicitreturn statement. Unfortunately, the absolute value of0 is0, notNone.
To fix this problem, you can add a thirdreturn statement, either in a newelif clause or in a finalelse clause:
>>>defmy_abs(number):...ifnumber>0:...returnnumber...elifnumber<0:...return-number...else:...return0...>>>my_abs(0)0>>>my_abs(-15)15>>>my_abs(15)15Now,my_abs() checks every possible condition,number > 0,number < 0, andnumber == 0. The purpose of this example is to show that when you’re using conditional statements to provide multiplereturn statements, you need to make sure that every possible option gets its ownreturn statement. Otherwise, your function will have a hidden bug.
Finally, you can implementmy_abs() in a more concise, efficient, andPythonic way using a singleif statement:
>>>defmy_abs(number):...ifnumber<0:...return-number...returnnumber...>>>my_abs(0)0>>>my_abs(-15)15>>>my_abs(15)15In this case, your function hits the firstreturn statement ifnumber < 0. In all other cases, whethernumber > 0 ornumber == 0, it hits the secondreturn statement. With this new implementation, your function looks a lot better. It’s more readable, concise, and efficient.
Note: There’s a convenient built-in Python function calledabs() for computing the absolute value of a number. The function in the above example is intended only to illustrate the point under discussion.
If you’re usingif statements to provide severalreturn statements, then you don’t need anelse clause to cover the last condition. Just add areturn statement at the end of the function’s code block and at the first level of indentation.
ReturningTrue orFalse
Another common use case for the combination ofif andreturn statements is when you’re coding apredicate orBoolean-valued function. This kind of function returns eitherTrue orFalse according to a given condition.
For example, say you need to write a function that takes two integers,a andb, and returnsTrue ifa is divisible byb. Otherwise, the function should returnFalse. Here’s a possible implementation:
>>>defis_divisible(a,b):...ifnota%b:...returnTrue...returnFalse...>>>is_divisible(4,2)True>>>is_divisible(7,4)Falseis_divisible() returnsTrue if the remainder of dividinga byb is equal to0. Otherwise, it returnsFalse. Note that in Python, a0 value isfalsy, so you need to use thenot operator to negate the truth value of the condition.
Sometimes you’ll write predicate functions that involve operators like the following:
- The comparison operators
==,!=,>,>=,<, and<= - The membership operator
in - The identity operator
is - The Boolean operator
not
In these cases, you can directly use aBoolean expression in yourreturn statement. This is possible because these operators return eitherTrue orFalse. Following this idea, here’s a new implementation ofis_divisible():
>>>defis_divisible(a,b):...returnnota%b...>>>is_divisible(4,2)True>>>is_divisible(7,4)FalseIfa is divisible byb, thena % b returns0, which is falsy in Python. So, to returnTrue, you need to use thenot operator.
Note: Python follows a set of rules to determine the truth value of an object.
For example, the following objects areconsidered falsy:
- Constants like
NoneandFalse - Numeric types with a zero value like
0,0.0,0j,Decimal(0), andFraction(0, 1) - Empty sequences and collections like
"",(),[],{},set(), andrange(0) - Objects that implement
__bool__()with a return value ofFalseor__len__()with a return value of0
Any other object will be considered truthy.
On the other hand, if you try to use conditions that involve Boolean operators likeor andand in the way you saw before, then your predicate functions won’t work correctly. That’s because these operators behave differently. They return one of the operands in the condition rather thanTrue orFalse:
>>>0and10>>>1and22>>>1or21>>>0or11In general,and returns the first false operand or the last operand. On the other hand,or returns the first true operand or the last operand. So, to write a predicate that involves one of these operators, you’ll need to use an explicitif statement or a call to the built-in functionbool().
Suppose you want to write a predicate function that takes two values and returnsTrue if both are true andFalse otherwise. Here’s your first approach to this function:
>>>defboth_true(a,b):...returnaandb...>>>both_true(1,2)2Sinceand returns operands instead ofTrue orFalse, your function doesn’t work correctly. There are at least three possibilities for fixing this problem:
- An explicit
ifstatement - Aconditional expression (ternary operator)
- The built-in Python function
bool()
If you use the first approach, then you can writeboth_true() as follows:
>>>defboth_true(a,b):...ifaandb:...returnTrue...returnFalse...>>>both_true(1,2)True>>>both_true(1,0)FalseTheif statement checks ifa andb are both truthy. If so, thenboth_true() returnsTrue. Otherwise, it returnsFalse.
If, on the other hand, you use a Python conditional expression or ternary operator, then you can write your predicate function as follows:
>>>defboth_true(a,b):...returnTrueifaandbelseFalse...>>>both_true(1,2)True>>>both_true(1,0)FalseHere, you use a conditional expression to provide a return value forboth_true(). The conditional expression is evaluated toTrue if botha andb are truthy. Otherwise, the final result isFalse.
Finally, if you usebool(), then you can codeboth_true() as follows:
>>>defboth_true(a,b):...returnbool(aandb)...>>>both_true(1,2)True>>>both_true(1,0)Falsebool() returnsTrue ifa andb are true andFalse otherwise. It’s up to you what approach to use for solving this problem. However, the second solution seems more readable. What do you think?
Short-Circuiting Loops
Areturn statement inside a loop performs some kind ofshort-circuit. It breaks the loop execution and makes the function return immediately. To better understand this behavior, you can write a function that emulatesany(). This built-in function takes an iterable and returnsTrue if at least one of its items is truthy.
To emulateany(), you can code a function like the following:
>>>defmy_any(iterable):...foriteminiterable:...ifitem:...# Short-circuit...returnTrue...returnFalse>>>my_any([0,0,1,0,0])True>>>my_any([0,0,0,0,0])FalseIf anyitem initerable is true, then the flow of execution enters in theif block. Thereturn statement breaks the loop and returns immediately with a return value ofTrue. If no value initerable is true, thenmy_any() returnsFalse.
This function implements ashort-circuit evaluation. For example, suppose that you pass an iterable that contains a million items. If the first item in that iterable happens to be true, then the loop runs only one time rather than a million times. This can save you a lot of processing time when running your code.
It’s important to note that to use areturn statement inside a loop, you need to wrap the statement in anif statement. Otherwise, the loop will always break in its first iteration.
Recognizing Dead Code
As soon as a function hits areturn statement, it terminates without executing any subsequent code. Consequently, the code that appears after the function’sreturn statement is commonly calleddead code. The Python interpreter totally ignores dead code when running your functions. So, having that kind of code in a function is useless and confusing.
Consider the following function, which adds code after itsreturn statement:
>>>defdead_code():...return42...# Dead code...print("Hello, World")...>>>dead_code()42The statementprint("Hello, World") in this example will never execute because that statement appears after the function’sreturn statement. Identifying dead code and removing it is a good practice that you can apply to write better functions.
It’s worth noting that if you’re using conditional statements to provide multiplereturn statements, then you can have code after areturn statement that won’t be dead as long as it’s outside theif statement:
>>>defno_dead_code(condition):...ifcondition:...return42...print("Hello, World")...>>>no_dead_code(True)42>>>no_dead_code(False)Hello, WorldEven though the call toprint() is after areturn statement, it’s not dead code. Whencondition is evaluated toFalse, theprint() call is run and you getHello, World printed to your screen.
Returning Multiple Named-Objects
When you’re writing a function that returns multiple values in a singlereturn statement, you can consider using acollections.namedtuple object to make your functions more readable.namedtuple is a collection class that returns a subclass oftuple that has fields or attributes. You can access those attributes usingdot notation or anindexing operation.
The initializer ofnamedtuple takes several arguments. However, to start usingnamedtuple in your code, you just need to know about the first two:
typenameholds the name of the tuple-like class that you’re creating. It needs to be a string.field_namesholds the names of the fields or attributes of the tuple-like class. It can be a sequence of strings such as["x", "y"]or a single string with each name separated by whitespace or commas, such as"x y"or"x, y".
Using anamedtuple when you need to return multiple values can make your functions significantly more readable without too much effort. Consider the following update ofdescribe() using anamedtuple as a return value:
importstatisticsasstfromcollectionsimportnamedtupledefdescribe(sample):Desc=namedtuple("Desc",["mean","median","mode"])returnDesc(st.mean(sample),st.median(sample),st.mode(sample),)Insidedescribe(), you create anamedtuple calledDesc. This object can have named attributes that you can access by using dot notation or by using an indexing operation. In this example, those attributes are"mean","median", and"mode".
You can create aDesc object and use it as a return value. To do that, you need to instantiateDesc like you’d do with any Python class. Note that you need to supply a concrete value for each named attribute, just like you did in yourreturn statement.
Here’s howdescribe() works now:
>>>sample=[10,2,4,7,9,3,9,8,6,7]>>>stat_desc=describe(sample)>>>stat_descDesc(mean=5.7, median=6.0, mode=6)>>># Get the mean by its attribute name>>>stat_desc.mean5.7>>># Get the median by its index>>>stat_desc[1]6.0>>># Unpack the values into three variables>>>mean,median,mode=describe(sample)>>>mean5.7>>>mode6When you calldescribe() with a sample of numeric data, you get anamedtuple object containing the mean, median, and mode of the sample. Note that you can access each element of the tuple by using either dot notation or an indexing operation.
Finally, you can also use an iterable unpacking operation to store each value in its own independent variable.
Returning Functions: Closures
In Python, functions arefirst-class objects. A first-class object is an object that can be assigned to a variable, passed as an argument to a function, or used as a return value in a function. So, you can use a function object as a return value in anyreturn statement.
A function that takes a function as an argument, returns a function as a result, or both is ahigher-order function. Aclosure factory function is a common example of a higher-order function in Python. This kind of function takes some arguments and returns aninner function. The inner function is commonly known as aclosure.
A closure carries information about its enclosing execution scope. This provides a way to retain state information between function calls. Closure factory functions are useful when you need to write code based on the concept oflazy or delayed evaluation.
Suppose you need to write a helper function that takes a number and returns the result of multiplying that number by a given factor. You can code that function as follows:
defby_factor(factor,number):returnfactor*numberby_factor() takesfactor andnumber as arguments and returns their product. Sincefactor rarely changes in your application, you find it annoying to supply the same factor in every function call. So, you need a way to retain the state or value offactor between calls toby_factor() and change it only when needed. To retain the current value offactor between calls, you can use a closure.
The following implementation ofby_factor() uses a closure to retain the value offactor between calls:
>>>defby_factor(factor):...defmultiply(number):...returnfactor*number...returnmultiply...>>>double=by_factor(2)>>>double(3)6>>>double(4)8>>>triple=by_factor(3)>>>triple(3)9>>>triple(4)12Insideby_factor(), you define an inner function calledmultiply() and return it without calling it. The function object you return is a closure that retains information about the state offactor. In other words, it remembers the value offactor between calls. That’s whydouble remembers thatfactor was equal to2 andtriple remembers thatfactor was equal to3.
Note that you can freely reusedouble andtriple because they don’t forget their respective state information.
You can also use alambda function to create closures. Sometimes the use of alambda function can make your closure factory more concise. Here’s an alternative implementation ofby_factor() using alambda function:
>>>defby_factor(factor):...returnlambdanumber:factor*number...>>>double=by_factor(2)>>>double(3)6>>>double(4)8This implementation works just like the original example. In this case, the use of alambda function provides a quick and concise way to codeby_factor().
Taking and Returning Functions: Decorators
Another way of using thereturn statement for returning function objects is to writedecorator functions. Adecorator function takes a function object as an argument and returns a function object. The decorator processes the decorated function in some way and returns it or replaces it with another function or callable object.
Decorators are useful when you need to add extra logic to existing functions without modifying them. For example, you can code a decorator to log function calls, validate the arguments to a function, measure the execution time of a given function, and so on.
The following example shows a decorator function that you can use to get an idea of the execution time of a given Python function:
>>>importtime>>>defmy_timer(func):...def_timer(*args,**kwargs):...start=time.time()...result=func(*args,**kwargs)...end=time.time()...print(f"Execution time:{end-start}")...returnresult...return_timer...>>>@my_timer...defdelayed_mean(sample):...time.sleep(1)...returnsum(sample)/len(sample)...>>>delayed_mean([10,2,4,7,9,3,9,8,6,7])Execution time: 1.00110960006713876.5The syntax@my_timer above the header ofdelayed_mean() is equivalent to the expressiondelayed_mean = my_timer(delayed_mean). In this case, you can say thatmy_timer() is decoratingdelayed_mean().
Python runs decorator functions as soon as youimport or run a module or a script. So, when you calldelayed_mean(), you’re really calling the return value ofmy_timer(), which is the function object_timer. The call to the decorateddelayed_mean() will return the mean of the sample and will also measure the execution time of the originaldelayed_mean().
In this case, you usetime() to measure the execution time inside the decorator.time() lives in a module calledtime that provides a set of time-related functions.time() returns the time in seconds since theepoch as a floating-point number. The difference between the time before and after the call todelayed_mean() will give you an idea of the function’s execution time.
Note: Indelayed_mean(), you use the functiontime.sleep(), which suspends the execution of the calling code for a given number of seconds. For a better understanding on how to usesleep(), check outPython sleep(): How to Add Time Delays to Your Code.
Other common examples of decorators in Python areclassmethod(),staticmethod(), andproperty(). If you want to dive deeper into Python decorators, then take a look atPrimer on Python Decorators. You can also check outPython Decorators 101.
Returning User-Defined Objects: The Factory Pattern
The Pythonreturn statement can also returnuser-defined objects. In other words, you can use your own custom objects as a return value in a function. A common use case for this capability is thefactory pattern.
The factory pattern defines an interface for creating objects on the fly in response to conditions that you can’t predict when you’re writing a program. You can implement a factory of user-defined objects using a function that takes some initialization arguments and returns different objects according to the concrete input.
Say you’re writing a painting application. You need to create different shapes on the fly in response to your user’s choices. Your program will have squares, circles, rectangles, and so on. To create those shapes on the fly, you first need to create the shape classes that you’re going to use:
classCircle:def__init__(self,radius):self.radius=radius# Class implementation...classSquare:def__init__(self,side):self.side=side# Class implementation...Once you have a class for each shape, you can write a function that takes the name of the shape as a string and an optional list ofarguments (*args) and keyword arguments (**kwargs) to create and initialize shapes on the fly:
defshape_factory(shape_name,*args,**kwargs):shapes={"circle":Circle,"square":Square}returnshapes[shape_name](*args,**kwargs)This function creates an instance of the concrete shape and returns it to the caller. Now you can useshape_factory() to create objects of different shapes in response to the needs of your users:
>>>circle=shape_factory("circle",radius=20)>>>type(circle)<class '__main__.Circle'>>>>circle.radius20>>>square=shape_factory("square",side=10)>>>type(square)<class '__main__.Square'>>>>square.side10If you callshape_factory() with the name of the required shape as a string, then you get a new instance of the shape that matches theshape_name you’ve just passed to the factory.
Usingreturn intry …finally Blocks
When you use areturn statement inside atry statement with afinally clause, thatfinally clause is always executed before thereturn statement. This ensures that the code in thefinally clause will always run. Check out the following example:
>>>deffunc(value):...try:...returnfloat(value)...exceptValueError:...returnstr(value)...finally:...print("Run this before returning")...>>>func(9)Run this before returning9.0>>>func("one")Run this before returning'one'When you callfunc(), you getvalue converted to a floating-point number or a string object. Before doing that, your function runs thefinally clause and prints a message to your screen. Whatever code you add to thefinally clause will be executed before the function runs itsreturn statement.
Usingreturn in Generator Functions
A Python function with ayield statement in its body is agenerator function. When you call a generator function, it returns agenerator iterator. So, you can say that a generator function is agenerator factory.
You can use areturn statement inside a generator function to indicate that the generator is done. Thereturn statement will make the generator raise aStopIteration. The return value will be passed as an argument to the initializer ofStopIteration and will be assigned to its.value attribute.
Here’s a generator that yields1 and2 on demand and then returns3:
>>>defgen():...yield1...yield2...return3...>>>g=gen()>>>g<generator object gen at 0x7f4ff4853c10>>>>next(g)1>>>next(g)2>>>next(g)Traceback (most recent call last): File"<input>", line1, in<module>next(g)StopIteration:3gen() returns a generator object that yields1 and2 on demand. To retrieve each number form the generator object, you can usenext(), which is a built-in function that retrieves the next item from a Python generator.
The first two calls tonext() retrieve1 and2, respectively. In the third call, the generator is exhausted, and you get aStopIteration. Note that the return value of the generator function (3) becomes the.value attribute of theStopIteration object.
FAQs
The Pythonreturn statement allows you to send any Python object from yourcustom functions back to the caller code. This statement is a fundamental part of any Python function or method. If you master how to use it, then you’ll be ready to code robust functions.
Next, you’ll find common questions that sum up the most important concepts you’ve learned in this tutorial. You can use these questions to check, recap, and solidify your knowledge. After each question, you’ll find an answer hidden in a collapsible section. Click theShow/Hide toggle to reveal it. But first, try to come up with the answer on your own.
An explicitreturn statement immediately ends the function’s execution and sends the specified value back to the caller. For example, a function can return a number, a list, or any other object. If no return statement is present, Python adds one implicitly, which returnsNone.
In Python, thereturn statement allows you to send values back to the caller from a function. To return a single value, use thereturn keyword followed by the value. This can be any data type, such as a number, string, list, or object.
To return multiple values, list them after the return keyword separated by commas. Python packs these values into a tuple. You can then unpack the tuple into separate variables or store it as a single variable.
First, explicitly returnNone when appropriate. If your function should returnNone, do so explicitly withreturn None for clarity. However, if your function performs actions without a clear return value, you can omit thereturn statement and rely on Python implicitly returningNone.
Additionally, avoid complex return expressions. Instead, break them down to improve readability and debugging. You can also use short-circuiting in loops to simplify your code. Employreturn statements inside loops to exit early when a condition is met, saving processing time.
You should also prefer self-contained functions over those that modify global variables, and when using conditional returns, handle all possible conditions with appropriate return statements to avoid hidden bugs.
Creating aclosure factory function involves making a function that returns another function. This inner function retains access to the variables from the outer function. It’s perfect for situations where you want to keep some state information between calls.
Fordecorator functions, you write a function that takes another function, adds some extra functionality, and returns this new function. Decorators are great for tasks like logging and timing that aren’t central to the original function’s purpose.
Do you want to take a quick quiz to evaluate your new skills? If so, then click the link below:
Take the Quiz: Test your knowledge with our interactive “The Python return Statement” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
The Python return StatementIn this quiz, you can practice your understanding of how to use the Python return statement when writing functions. Additionally, you'll cover some good programming practices related to the use of return. With this knowledge, you'll be able to write readable, robust, and maintainable functions in Python.
Recommended Course
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

AboutLeodanis Pozo Ramos
Leodanis is a self-taught Python developer, educator, and technical writer with over 10 years of experience.
» More about LeodanisMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Looking for a real-time conversation? Visit theReal Python Community Chat or join the next“Office Hours” Live Q&A Session. Happy Pythoning!
Keep Learning
Keep reading Real Python by creating a free account or signing in:
Already have an account?Sign-In







