275 lines
12 KiB
Markdown
275 lines
12 KiB
Markdown
|
|
# Python 函数:代码重用的基础
|
|||
|
|
|
|||
|
|
> 原文:[https://python.land/introduction-to-python/functions](https://python.land/introduction-to-python/functions)
|
|||
|
|
|
|||
|
|
函数是编程世界中一个至关重要的概念。在本文中,我们将探索 Python 函数。您将了解为什么它们如此重要,如何用 Python 的 def 关键字定义函数,如何调用函数,并且我们将了解使用函数时出现的一个主题:变量范围。
|
|||
|
|
|
|||
|
|
目录
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
* [Python 中的函数是什么?](#What_is_a_function_in_Python "What is a function in Python?")
|
|||
|
|
* [使用功能的优势](#Advantages_of_using_functions "Advantages of using functions")
|
|||
|
|
* [内置 Python 函数](#Built-in_Python_functions "Built-in Python functions")
|
|||
|
|
* [创建 Python 函数](#Creating_a_Python_function "Creating a Python function")
|
|||
|
|
* [缩进](#Indentation "Indentation")
|
|||
|
|
* [Python 函数参数和自变量](#Python_function_parameters_and_arguments "Python function parameters and arguments")
|
|||
|
|
* [从函数返回](#Returning_from_a_function "Returning from a function")
|
|||
|
|
* [返回值](#Returning_values "Returning values")
|
|||
|
|
* [变量范围](#Variable_scope "Variable scope")
|
|||
|
|
* [默认值和命名参数](#Default_values_and_named_parameters "Default values and named parameters")
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
## Python 中的函数是什么?
|
|||
|
|
|
|||
|
|
让我们确切地定义一下什么是函数:
|
|||
|
|
|
|||
|
|
**Function**
|
|||
|
|
|
|||
|
|
A Python function is a named section of a program that performs a specific task and, optionally, returns a value
|
|||
|
|
|
|||
|
|
函数是任何编程语言的真正组成部分。我们用关键字`def`定义了一个 Python 函数。但是在我们开始这样做之前,让我们先回顾一下函数的优点,让我们看看一些您可能已经知道的内置函数。
|
|||
|
|
|
|||
|
|
## 使用功能的优势
|
|||
|
|
|
|||
|
|
### 代码重用
|
|||
|
|
|
|||
|
|
Python 函数可以定义一次,使用多次。因此,它有助于代码重用:您不会希望多次编写相同的代码。
|
|||
|
|
|
|||
|
|
函数是保持代码短小、简洁、易读的好方法。通过给函数起一个精心选择的名字,你的代码将变得更加易读,因为函数名直接解释了将会发生什么。这样,其他人(或者将来的你)就可以阅读你的代码,而且不用看全部,也能理解它在做什么,因为它有精心选择的函数名。
|
|||
|
|
|
|||
|
|
稍后将解释代码重用的其他形式。例如,你也可以将代码分组到[模块](https://python.land/project-structure/python-modules)和[包](https://python.land/project-structure/python-packages)中。
|
|||
|
|
|
|||
|
|
### 因素
|
|||
|
|
|
|||
|
|
函数接受一个参数,稍后您将看到它是如何工作的。这里最大的优点是,你可以通过改变参数来改变函数的行为。
|
|||
|
|
|
|||
|
|
### 返回值
|
|||
|
|
|
|||
|
|
函数可以返回值。该值通常是某种计算或运算的结果。事实上,一个 Python 函数甚至可以[返回多个值](https://python.land/return-multiple-values-from-function)。
|
|||
|
|
|
|||
|
|
## 内置 Python 函数
|
|||
|
|
|
|||
|
|
在我们开始自己定义函数之前,我们先来看看 Python 的一些内置函数。先说最广为人知的内置函数,叫做`print`:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> print('Hello, readers!')
|
|||
|
|
Hello, readers!
|
|||
|
|
>>> print(15)
|
|||
|
|
15
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Print 接受一个参数并将其打印到屏幕上。
|
|||
|
|
|
|||
|
|
正如我们的定义中所述,函数可以选择返回值。但是,`print`不返回任何东西。因为它把一些东西打印到屏幕上,看起来好像是这样,但实际上不是。我们可以通过将打印语句的结果赋给一个 [Python 变量](https://python.land/introduction-to-python/variable)来检查这一点:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> result = print('Hello')
|
|||
|
|
Hello
|
|||
|
|
>>> print(result)
|
|||
|
|
None
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`None`是 Python 中一种特殊类型的值,基本意思是“什么都不是”
|
|||
|
|
|
|||
|
|
另一个确实返回值的内置函数是`len()`。它返回你喂它的任何东西的长度:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> mylength = len('Hello')
|
|||
|
|
>>> print(mylength)
|
|||
|
|
5
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 创建 Python 函数
|
|||
|
|
|
|||
|
|
现在我们知道了如何使用函数,让我们自己创建一个简单的函数。为此,我们使用 Python 的`def`关键字:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def say_hi():
|
|||
|
|
... print('Hi!')
|
|||
|
|
...
|
|||
|
|
>>> say_hi()
|
|||
|
|
Hi!
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
虽然只有几行,但很多事情都在进行。让我们仔细分析一下:
|
|||
|
|
|
|||
|
|
* 首先我们看到关键字`def`,这是 Python 定义一个函数的关键字。
|
|||
|
|
* 接下来是我们的函数名,say_hi。
|
|||
|
|
* 然后我们遇到两个括号,(),表示这个函数不接受任何参数(不像`print`和`len`)。
|
|||
|
|
* 我们用冒号(:)结束这一行
|
|||
|
|
* 最后,我们遇到了一个使 Python 区别于许多其他编程语言的特性:缩进。
|
|||
|
|
|
|||
|
|
## 缩进
|
|||
|
|
|
|||
|
|
Python 使用缩进来区分属于一起的代码块。具有相同缩进的连续行是同一代码块的一部分。
|
|||
|
|
|
|||
|
|
为了告诉 Python 下面几行是我们函数的主体,我们需要缩进它们。你用键盘上的**键**键**键**来缩进行。在 Python 中,使用四个空格进行缩进是一种很好的风格。整个 Python 社区都这样做。如果你点击 TAB 键,Python 交互式 shell (REPL)和所有像样的编辑器将自动缩进四个空格。
|
|||
|
|
|
|||
|
|
Thank you for reading my tutorials. I write these in my free time, and it requires a lot of time and effort. I use ads to keep writing these *free* articles, I hope you understand! **Support me by disabling your adblocker on my website** or, alternatively, **[buy me some coffee](https://www.buymeacoffee.com/pythonland)**. It's much appreciated and allows me to keep working on this site!
|
|||
|
|
|
|||
|
|
回到我们的函数:它的主体只有一行代码:print 命令。在此之后,我们再按一次 enter 键,让 Python REPL 知道这是函数的结尾。这很重要。函数后面必须有一个空行来表示函数的结束。最后,我们可以用`say_hi()`调用我们的函数。
|
|||
|
|
|
|||
|
|
## Python 函数参数和自变量
|
|||
|
|
|
|||
|
|
我们可以通过将一个参数传递给我们的函数来使这变得更有趣。我们再次用 def 定义了一个函数,但是我们在括号之间添加了一个变量名:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def say_hi(name):
|
|||
|
|
... print('Hi', name)
|
|||
|
|
...
|
|||
|
|
>>> say_hi('Erik')
|
|||
|
|
Hi Erik
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
我们的函数现在接受一个值,该值被赋给变量名。我们将这样的变量称为**参数**,而我们提供的实际值(‘Erik’)称为**参数**。
|
|||
|
|
|
|||
|
|
**Parameters and arguments**
|
|||
|
|
|
|||
|
|
A Python function can have parameters. The values we pass through these parameters are called arguments.
|
|||
|
|
|
|||
|
|
如您所见,`print()`接受多个参数,用逗号分隔。这允许我们打印“hi”和提供的姓名。为了方便起见,`print()`会自动在两个字符串之间加一个空格。
|
|||
|
|
|
|||
|
|
### 具有多个参数的 Python 函数
|
|||
|
|
|
|||
|
|
让我们更进一步,定义一个有多个参数的函数:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def welcome(name, location):
|
|||
|
|
... print("Hi", name, "welcome to", location)
|
|||
|
|
...
|
|||
|
|
>>> welcome('Erik', 'this tutorial')
|
|||
|
|
Hi Erik welcome to this tutorial
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
没那么难;您只需在函数定义中添加更多的参数,用逗号分隔。
|
|||
|
|
|
|||
|
|
## 从函数返回
|
|||
|
|
|
|||
|
|
一个函数运行到该函数结束,之后 Python 返回到调用该函数的地方。在下面的示例中,我希望您在运行之前预测输出:
|
|||
|
|
|
|||
|
|
[https://crumb.sh/embed/k2pkTYQVGMW](https://crumb.sh/embed/k2pkTYQVGMW)
|
|||
|
|
|
|||
|
|
预测这个程序的输出
|
|||
|
|
|
|||
|
|
你的期望与现实相符吗?如果是这样,那么您已经很好地理解了函数调用是如何工作的。在这一点上,有些人希望看到文本“让我们问候整个世界”两次。如果你是其中之一,不要着急,继续读下去。
|
|||
|
|
|
|||
|
|
Python 会跟踪函数的调用点。在我们的例子中,它在第 5 行。一旦被调用,Python 就会一行一行地运行函数中的代码块,直到到达函数的末尾。一旦到达函数的末尾, *Python 会跳回到从*调用函数的那一行:第 6 行!
|
|||
|
|
|
|||
|
|
简而言之:函数调用不是跳转或“转到”,而是对一段可重用代码的调用,这段代码返回到它被调用的地方。函数调用也是一个表达式:大多数函数都返回值。
|
|||
|
|
|
|||
|
|
## 返回值
|
|||
|
|
|
|||
|
|
到目前为止,我们的函数只打印了一些东西,没有返回任何东西。使函数更有用的是返回值的能力。让我们看一个 Python 函数如何返回值的示例:
|
|||
|
|
|
|||
|
|
[https://crumb.sh/embed/QdrfCWZeXKu](https://crumb.sh/embed/QdrfCWZeXKu)
|
|||
|
|
|
|||
|
|
这是从 Python 函数返回值的方式
|
|||
|
|
|
|||
|
|
如您所见,我们使用关键字`return`从函数中返回值。返回值的函数可以用在任何我们可以使用表达式的地方。在上面的例子中,我们可以将返回值赋给变量`result`。
|
|||
|
|
|
|||
|
|
我们也可以在 if 语句中使用该函数。例如:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
if add(1, 1) == 2:
|
|||
|
|
print("That's what you'd expect!")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 空 return 语句
|
|||
|
|
|
|||
|
|
如果你的函数不返回任何东西,但是你仍然想从函数返回,你可以使用一个空的 return 语句。这里有一个愚蠢的例子:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
def optional_greeter(name):
|
|||
|
|
if name.startswith('X'):
|
|||
|
|
# We don't greet people with weird names :p
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print('Hi there, ', name)
|
|||
|
|
|
|||
|
|
optional_greeter('Xander')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这是一个有趣的模式;我称之为提前回归。我想早点回来,因为另一种选择是使用 if… else 语句块:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
def optional_greeter(name):
|
|||
|
|
if name.startswith('X'):
|
|||
|
|
# We don't greet people with weird names :p
|
|||
|
|
pass
|
|||
|
|
else:
|
|||
|
|
print('Hi there, ', name)
|
|||
|
|
|
|||
|
|
optional_greeter('Xander')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
你觉得哪个看起来更干净?我认为是第一种,因为它需要更少的缩进代码。虽然对于这样一个小例子来说差别很小,但是当你有更大的代码块时,这种差别就开始增加了。
|
|||
|
|
|
|||
|
|
## 变量范围
|
|||
|
|
|
|||
|
|
变量`name`只存在于我们的函数内部。我们说变量`name`的范围限于函数`say_hi`,意味着它不存在于这个函数之外。
|
|||
|
|
|
|||
|
|
**Scope**
|
|||
|
|
|
|||
|
|
The visibility of a variable is called scope. The scope defines which parts of your program can see and use a variable.
|
|||
|
|
|
|||
|
|
如果我们在所谓的程序顶层定义一个变量,那么它在任何地方都是可见的。
|
|||
|
|
|
|||
|
|
让我们来演示一下:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def say_hi():
|
|||
|
|
... print("Hi", name)
|
|||
|
|
... answer = "Hi"
|
|||
|
|
...
|
|||
|
|
>>> name = 'Erik'
|
|||
|
|
>>> say_hi()
|
|||
|
|
Hi Erik
|
|||
|
|
>>> print(answer)
|
|||
|
|
Traceback (most recent call last):
|
|||
|
|
File "<stdin>", line 1, in <module>
|
|||
|
|
NameError: name 'answer' is not defined
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`say_hi`能够像预期的那样使用变量`name`,因为它是一个顶级变量:它随处可见。然而,在 say_hi 内部定义的`answer`在函数之外是未知的,并且会导致`NameError`。Python 给出了一个信息性的详细错误:“名称‘答案’未定义。”
|
|||
|
|
|
|||
|
|
## 默认值和命名参数
|
|||
|
|
|
|||
|
|
Python 的一个引人注目的特性是能够为参数提供默认值:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def welcome(name='learner', location='this tutorial'):
|
|||
|
|
... print("Hi", name, "welcome to", location)
|
|||
|
|
...
|
|||
|
|
>>> welcome()
|
|||
|
|
Hi learner welcome to this tutorial
|
|||
|
|
>>> welcome(name='John')
|
|||
|
|
Hi John welcome to this tutorial
|
|||
|
|
>>> welcome(location='this epic tutorial')
|
|||
|
|
Hi learner welcome to this epic tutorial
|
|||
|
|
>>> welcome(name='John', location='this epic tutorial')
|
|||
|
|
Hi John welcome to this epic tutorial
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
或者,如果您愿意,可以使用下面的交互式示例:
|
|||
|
|
|
|||
|
|
[https://crumb . sh/embed/3gqc 9 ebqd 3k](https://crumb.sh/embed/3GQC9eBqd3k)
|
|||
|
|
|
|||
|
|
默认值和命名参数的演示
|
|||
|
|
|
|||
|
|
因为我们的参数有一个默认值,所以您不必填写它们。如果没有,则使用默认值。如果这样做,您可以用自己的值覆盖默认值。
|
|||
|
|
|
|||
|
|
在显式命名参数的同时调用 Python 函数与我们迄今为止所做的不同。这些参数称为命名参数,因为我们指定了名称和值,而不仅仅是值。由于这些命名的参数,我们提供它们的顺序并不重要。仔细想想,这是让默认值变得有用的自然且唯一的方法。
|
|||
|
|
|
|||
|
|
如果你不想使用命名参数,你可以。当你依赖位置而不是名字时,你提供了我们所说的位置参数。位置很重要,如下所示:
|
|||
|
|
|
|||
|
|
```py
|
|||
|
|
>>> def welcome(name='learner', location='this tutorial'):
|
|||
|
|
... print("Hi", name, "welcome to", location)
|
|||
|
|
...
|
|||
|
|
>>> welcome('Erik', 'your home')
|
|||
|
|
Hi Erik welcome to your home
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
现在,您已经学习了足够多的函数知识,可以继续学习本教程。如果你想了解更多,请阅读我的 [Python 函数深潜](https://python.land/deep-dives/functions)。
|