- Что делает return в Python?
- Пример
- Вывод
- Пример оператора return Python
- Каждая функция что-то возвращает
- Что произойдет, если в операторе ничего нет?
- Может иметь несколько операторов
- Функция может возвращать несколько типов значений
- Возврат нескольких значений в одном операторе
- С блоком finally
- Is there a way to do more work after a return statement?
- 11 Answers 11
Что делает return в Python?
Функция print() записывает, то есть «печатает», строку или число на консоли. Оператор return не выводит значение, которое возвращается при вызове функции. Это, однако, приводит к немедленному завершению или завершению функции, даже если это не последний оператор функции.
Во многих других языках функция, которая не возвращает значение, называется процедурой.
В данном коде значение, возвращаемое (то есть 2) при вызове функции foo(), используется в функции bar(). Эти возвращаемые значения печатаются на консоли только тогда, когда используются операторы печати, как показано ниже.
Пример
def foo(): print("Hello from within foo") return 2 def bar(): return 10*foo() print foo() print bar()
Вывод
Hello from within foo 2 Hello from within foo 20
Мы видим, что когда foo() вызывается из bar(), 2 не записывается в консоль. Вместо этого он используется для вычисления значения, возвращаемого из bar().
Пример оператора return Python
Давайте посмотрим на простой пример сложения двух чисел и возврата суммы вызывающему абоненту.
def add(x, y): total = x + y return total
Мы можем оптимизировать функцию, указав выражение в операторе возврата.
Каждая функция что-то возвращает
Давайте посмотрим, что возвращается, когда функция не имеет оператора возврата.
>>> def foo(): . pass . >>> >>> print(foo()) None >>>
Что произойдет, если в операторе ничего нет?
Когда оператор return не имеет значения, функция возвращает None.
>>> def return_none(): . return . >>> print(return_none()) None >>>
Может иметь несколько операторов
def type_of_int(i): if i % 2 == 0: return 'even' else: return 'odd'
Функция может возвращать несколько типов значений
В отличие от других языков программирования, функции Python не ограничиваются возвратом значений одного типа. Если вы посмотрите на определение функции, в нем нет никакой информации о том, что она может вернуть.
Давайте посмотрим на пример, в котором функция возвращает несколько типов значений.
def get_demo_data(object_type): if 'str' == object_type: return 'test' elif 'tuple' == object_type: return (1, 2, 3) elif 'list' == object_type: return [1, 2, 3] elif 'dict' == object_type: return else: return None
Возврат нескольких значений в одном операторе
Мы можем вернуть несколько значений из одного оператора возврата. Эти значения разделяются запятой и возвращаются вызывающей программе в виде кортежа.
def return_multiple_values(): return 1, 2, 3 print(return_multiple_values()) print(type(return_multiple_values()))
С блоком finally
Как работает оператор return внутри блока try-except? Сначала выполняется код блока finally перед возвратом значения вызывающей стороне.
def hello(): try: return 'hello try' finally: print('finally block') def hello_new(): try: raise TypeError except TypeError as te: return 'hello except' finally: print('finally block') print(hello()) print(hello_new())
finally block hello try finally block hello except
Если в блоке finally есть оператор return, то предыдущий оператор return игнорируется и возвращается значение из блока finally.
def hello(): try: return 'hello try' finally: print('finally block') return 'hello from finally' print(hello())
finally block hello from finally
Is there a way to do more work after a return statement?
I was a bit curious if I could do more work in a function after returning a result. Basically I’m making a site using the pyramid framework(which is simply coding in python) after I process the inputs I return variables to render the page but sometimes I want to do more work after I render the page. For example, you come to my site and update your profile and all you care about is that its successful so I output a message saying ‘success!’ but after that done I want to take your update and update my activity logs of what your doing, update your friends activity streams, etc.. Right now I’m doing all that before I return the result status that you care about but I’m curious if I can do it after so users get their responses faster. I have done multi-processing before and worst case I might just fork a thread to do this work but if there was a way to do work after a return statement then that would be simpler. example:
def profile_update(inputs): #take updates and update the database return "it worked" #do maintenance processing now.
I’m not familiar with python’s threading, but most in threading models, starting up a thread is about as simple as calling a function. The complexity comes from making sure the work that’s done in the thread is synchronized appropriately with the stuff that’s happening asynchronously to the thread. It seems to me that complexity would exist to the same degree with whatever you might want to occur in the #do maintainence processing now.. post-return step. If no synchronization would be necessary there, then none should be necessary in a thread. But, the converse is also true.
11 Answers 11
You could still do some work after return if you return from a try-block, the finally-block would still be executed, e.g.:
def fun(x): try: return x * 20 finally: print("Yay! I still got executed, even though my function has already returned!") print(fun(5))
Yay! I still got executed, even though my function has already returned! 100
When return passes control out of a try statement with a finally clause, that finally clause is executed before really leaving the function.
But the finally would still run before the caller receives the returned value. This doesn’t help you allow the caller to receive a response and notify the user, but then run more code.
Depending on the use case, that might be fine. It could be a convenient flow control technique to wrap your function’s contents in try, and have a variety of different return statements, all of which would drop the flow directly to the finally block to perform maintenance.
@Ben This worked for me. I returned a class attribute in the try block then cleared the attribute in the finally block and the return value was correct.
Why don’t you use a contextmanager? It basically does exactly what you want.
Here’s the canonical example from the Python docs.
from contextlib import contextmanager @contextmanager def tag(name): print "<%s>" % name yield print "%s>" % name
So for your function, you’d just do:
@contextmanager def profile_update(inputs): #take updates and update the database yield "it worked" #do maintainence processing now..
And to call it, you’d just do:
with profile_update(inputs) as result: #pre-yield and yield here # do whatever while in scope # as you move out of scope of with statement, post-yield is executed
EDIT: I was just testing things out, and it turns out that, with a yield statement, the function still executes to the end. Here’s a dumb example that illustrates the point and when things get executed.
def some_generator(lst): for elem in lst: yield elem lst[0] = "I WAS CHANGED POST-YIELD. " >>> q = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> gen = some_generator(q) >>> for e in gen: . print e, q 0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 5 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 6 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 7 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 8 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 9 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print q ['I WAS CHANGED POST YIELD. ', 1, 2, 3, 4, 5, 6, 7, 8, 9]
A contextmanager has the advantage of not requiring two next calls to get to the stop iteration (and cleaner syntax), but if you wanted to return multiple values or something, you could also do it this way, but you can see that the post yield statement doesn’t actually get called until the generator raises StopIteration on the next call (the for loop ends when it gets StopIteration )
If for some reason, you require a higher degree of control than @contextmanager offers, you can also define a class with __enter__ and __exit__ methods:
class MyContextClass(object): # . def __enter__(self): # do some preprocessing return some_object def __exit__(self, exc_type, exc_value, traceback): # do some post processing # possibly do some processing of exceptions raised within the block if exc_type == MyCustomErrorType: return True #don't propagate the error