Как мне получить ("return") результат (output) из функции? Как я могу использовать результат позже?
Предположим, у меня есть функция типа:
def foo():
x = 'hello world'
Как мне вернуть функцию x
таким образом, чтобы я мог использовать ее в качестве входных данных для другой функции или использовать переменную в теле программы? Я пытался использовать return
, а затем использовать x
переменную в другой функции, но я получаю NameError
таким образом.
Для конкретного случая передачи информации между методами в одном классе часто лучше хранить информацию в self
. Подробнее см. в разделе Передача переменных между методами в Python? .
Переведено автоматически
Ответ 1
Вы можете использовать оператор return для возврата значения из функции, это не приводит к тому, что возвращаемая переменная (значение) становится доступной в области вызывающего объекта. Чтобы использовать значение в вызывающем объекте, вы можете либо использовать его непосредственно в инструкции, либо записать значение в переменной.
Вот некоторый код, демонстрирующий это:
def foo():
x = 'hello world'
return x # return 'hello world' would do, too
foo()
print(x) # NameError - x is not defined outside the function
y = foo()
print(y) # this works
x = foo()
print(x) # this also works, and it's a completely different x than that inside
# foo()
z = bar(x) # of course, now you can use x as you want
z = bar(foo()) # but you don't have to
Ответ 2
Фактически, есть два способа: прямой и косвенный.
Прямой способ - получить return
значение из функции, как вы уже пробовали, и позволить вызывающему коду использовать это значение. Это обычно то, что вы хотите. Естественный, простой, прямой и явный способ получить информацию обратно из функции - это return
it. Вообще говоря, цель функции - вычислить значение, и return
означает "это значение, которое мы вычислили; на этом мы закончили".
Прямое использование return
Главный трюк здесь в том, что return
возвращаетзначение, а не переменную. Таким образом, return x
не позволяет вызывающему коду использовать x
после вызова функции и не изменяет какое-либо существующее значение, которое x
было в контексте вызова. (Предположительно, поэтому вы получили NameError
.)
После того, как мы используем return
в функции:
def example():
x = 'hello world'
return x
нам нужно написать вызывающий код для использования возвращаемого значения:
result = example()
print(result)
Другим ключевым моментом здесь является то, что вызов функции является выражением, поэтому мы можем использовать его так же, как мы используем, скажем, результат сложения. Как мы можем сказать result = 'hello ' + 'world'
, мы можем сказать result = foo()
. После этого, result
это наше собственное, локальное имя для этой строки, и мы можем делать с ним все, что захотим.
Мы можем использовать то же имя, x
, если хотим. Или мы можем использовать другое имя. Вызывающий код не должен ничего знать о том, как написана функция или какие имена она использует для вещей.1
Мы можем использовать значение напрямую для вызова другой функции: например, print(foo())
.2 Мы можем возвращать значение напрямую: просто return 'hello world'
, без присвоения x
. (Опять же: мы возвращаем значение, а не переменную.)
Функция может выполняться только return
один раз при каждом вызове. return
завершает работу функции - опять же, мы только что определили результат вычисления, поэтому нет причин для дальнейших вычислений. Следовательно, если мы хотим вернуть несколько фрагментов информации, нам нужно будет создать один объект (в Python "значение" и "объект" фактически синонимичны; для некоторых других языков это работает не так хорошо.)
We can make a tuple right on the return line; or we can use a dictionary, a namedtuple
(Python 2.6+), a types.simpleNamespace
(Python 3.3+), a dataclass
(Python 3.7+), or some other class (perhaps even one we write ourselves) to associate names with the values that are being returned; or we can accumulate values from a loop in a list; etc. etc. The possibilities are endless..
On the other hand, the function return
s whether you like it or not (unless an exception is raised). If it reaches the end, it will implicitly return
the special value None
. You may or may not want to do it explicitly instead.
Indirect methods
Other than return
ing the result back to the caller directly, we can communicate it by modifying some existing object that the caller knows about. There are many ways to do that, but they're all variations on that same theme.
If you want the code to communicate information back this way, please just let it return None
- don't also use the return value for something meaningful. That's how the built-in functionality works.
In order to modify that object, the called function also has to know about it, of course. That means, having a name for the object that can be looked up in a current scope. So, let's go through those in order:
Local scope: Modifying a passed-in argument
If one of our parameters is mutable, we can just mutate it, and rely on the caller to examine the change. This is usually not a great idea, because it can be hard to reason about the code. It looks like:
def called(mutable):
mutable.append('world')
def caller():
my_value = ['hello'] # a list with just that string
called(my_value)
# now it contains both strings
If the value is an instance of our own class, we could also assign to an attribute:
class Test:
def __init__(self, value):
self.value = value
def called(mutable):
mutable.value = 'world'
def caller():
test = Test('hello')
called(test)
# now test.value has changed
Assigning to an attribute does not work for built-in types, including object
; and it might not work for some classes that explicitly prevent you from doing it.
Local scope: Modifying self
, in a method
We already have an example of this above: setting self.value
in the Test.__init__
code. This is a special case of modifying a passed-in argument; but it's part of how classes work in Python, and something we're expected to do. Normally, when we do this, the calling won't actually check for changes to self
- it will just use the modified object in the next step of the logic. That's what makes it appropriate to write code this way: we're still presenting an interface, so the caller doesn't have to worry about the details.
class Example:
def __init__(self):
self._words = ['hello']
def add_word(self):
self._words.append('world')
def display(self):
print(*self.words)
x = Example()
x.add_word()
x.display()
In the example, calling add_word
gave information back to the top-level code - but instead of looking for it, we just go ahead and call display
.3
See also: Passing variables between methods in Python?
Enclosing scope
This is a rare special case when using nested functions. There isn't a lot to say here - it works the same way as with the global scope, just using the nonlocal
keyword rather than global
.4
Global scope: Modifying a global
Generally speaking, it is a bad idea to change anything in the global scope after setting it up in the first place. It makes code harder to reason about, because anything that uses that global (aside from whatever was responsible for the change) now has a "hidden" source of input.
If you still want to do it, the syntax is straightforward:
words = ['hello']
def add_global_word():
words.append('world')
add_global_word() # `words` is changed
Global scope: Assigning to a new or existing global
This is actually a special case of modifying a global. I don't mean that assignment is a kind of modification (it isn't). I mean that when you assign a global name, Python automatically updates a dict that represents the global namespace. You can get that dict with globals()
, and you can modify that dict and it will actually impact what global variables exist. (I.e., the return from globals()
is the dictionary itself, not a copy.)5
But please don't. That's even worse of an idea than the previous one. If you really need to get the result from your function by assigning to a global variable, use the global
keyword to tell Python that the name should be looked up in the global scope:
words = ['hello']
def replace_global_words():
global words
words = ['hello', 'world']
replace_global_words() # `words` is a new list with both words
Global scope: Assigning to or modifying an attribute of the function itself
This is a rare special case, but now that you've seen the other examples, the theory should be clear. In Python, functions are mutable (i.e. you can set attributes on them); and if we define a function at top level, it's in the global namespace. So this is really just modifying a global:
def set_own_words():
set_own_words.words = ['hello', 'world']
set_own_words()
print(*set_own_words.words)
We shouldn't really use this to send information to the caller. It has all the usual problems with globals, and it's even harder to understand. But it can be useful to set a function's attributes from within the function, in order for the function to remember something in between calls. (It's similar to how methods remember things in between calls by modifying self
.) The functools
standard library does this, for example in the cache
implementation.
Builtin scope
This doesn't work. The builtin namespace doesn't contain any mutable objects, and you can't assign new builtin names (they'll go into the global namespace instead).
Some approaches that don't work in Python
Just calculating something before the function ends
In some other programming languages, there is some kind of hidden variable that automatically picks up the result of the last calculation, every time something is calculated; and if you reach the end of a function without return
ing anything, it gets returned. That doesn't work in Python. If you reach the end without return
ing anything, your function returns None
.
Assigning to the function's name
In some other programming languages, you are allowed (or expected) to assign to a variable with the same name as the function; and at the end of the function, that value is returned. That still doesn't work in Python. If you reach the end without return
ing anything, your function still returns None
.
def broken():
broken = 1
broken()
print(broken + 1) # causes a `TypeError`
It might seem like you can at least use the value that way, if you use the global
keyword:
def subtly_broken():
global subtly_broken
subtly_broken = 1
subtly_broken()
print(subtly_broken + 1) # 2
But this, of course, is just a special case of assigning to a global. And there's a big problem with it - the same name can't refer to two things at once. By doing this, the function replaced its own name. So it will fail next time:
def subtly_broken():
global subtly_broken
subtly_broken = 1
subtly_broken()
subtly_broken() # causes a `TypeError`
Assigning to a parameter
Sometimes people expect to be able to assign to one of the function's parameters, and have it affect a variable that was used for the corresponding argument. However, this does not work:
def broken(words):
words = ['hello', 'world']
data = ['hello']
broken(data) # `data` does not change
Just like how Python returns values, not variables, it also passes values, not variables. words
is a local name; by definition the calling code doesn't know anything about that namespace.
One of the working methods that we saw is to modify the passed-in list. That works because if the list itself changes, then it changes - it doesn't matter what name is used for it, or what part of the code uses that name. However, assigning a new list to words
does not cause the existing list to change. It just makes words
start being a name for a different list.
For more information, see How do I pass a variable by reference?.
1 At least, not for getting the value back. If you want to use keyword arguments, you need to know what the keyword names are. But generally, the point of functions is that they're an abstraction; you only need to know about their interface, and you don't need to think about what they're doing internally.
2 In 2.x, print
is a statement rather than a function, so this doesn't make an example of calling another function directly. However, print foo()
still works with 2.x's print statement, and so does print(foo())
(in this case, the extra parentheses are just ordinary grouping parentheses). Aside from that, 2.7 (the last 2.x version) has been unsupported since the beginning of 2020 - which was nearly a 5 year extension of the normal schedule. But then, this question was originally asked in 2010.
3Again: if the purpose of a method is to update the object, don't also return
a value. Some people like to return self
so that you can "chain" method calls; but in Python this is considered poor style. If you want that kind of "fluent" interface, then instead of writing methods that update self
, write methods that create a new, modified instance of the class.
4 Except, of course, that if we're modifying a value rather than assigning, we don't need either keyword.
5 There's also a locals()
that gives you a dict of local variables. However, this cannot be used to make new local variables - the behaviour is undefined in 2.x, and in 3.x the dict is created on the fly and assigning to it has no effect. Some of Python's optimizations depend on the local variables for a function being known ahead of time.
Ответ 3
>>> def foo():
return 'hello world'
>>> x = foo()
>>> x
'hello world'
Ответ 4
You can use global
statement and then achieve what you want without returning value from
the function. For example you can do something like below:
def foo():
global x
x = "hello world"
foo()
print x
The above code will print "hello world".
But please be warned that usage of "global" is not a good idea at all and it is better to avoid usage that is shown in my example.
Also check this related discussion on about usage of global statement in Python.