# Python 函数

> 原文： [http://zetcode.com/lang/python/functions/](http://zetcode.com/lang/python/functions/)

在 Python 编程教程的这一部分中，我们介绍了 Python 中的函数。

## Python 函数定义

函数是用于执行特定操作的可重用代码块。 使用函数的优点是：

*   减少代码重复
*   将复杂的问题分解成更简单的部分
*   提高代码的清晰度
*   重用代码
*   信息隐藏

Python 中的函数是一等公民。 这意味着函数与 Python 中的其他对象具有同等的状态。 可以将函数分配给变量，存储在集合中或作为参数传递。 这给语言带来了额外的灵活性。

## Python 函数类型

函数有两种基本类型：内置函数和用户定义函数。 内置函数是 Python 语言的一部分； 例如`dir()`，`len()`或`abs()`。 用户定义的函数是使用`def`关键字创建的函数。

## Python 创建函数

使用`def`关键字创建一个函数。 函数块中的语句必须缩进。

```py
def function():
    pass

```

`def`关键字后跟带有圆括号和冒号的函数名称。 缩进语句形成函数的主体。

该函数稍后在需要时执行。 我们说我们调用函数。 如果我们调用一个函数，则会执行函数体内的语句。 在调用函数之前，它们不会执行。

```py
myfunc()

```

要调用函数，我们用圆括号指定函数名称。

`ret.py`

```py
#!/usr/bin/env python

"""
The ret.py script shows how to work with
functions in Python.
Author: Jan Bodnar
ZetCode, 2019
"""

def show_module_name():

    print(__doc__)

def get_module_file():

    return __file__

a = show_module_name()
b = get_module_file()

print(a, b)

```

脚本顶部的字符串称为文档字符串。 它记录了当前脚本。 我们放入 Python 代码的文件称为模块。

我们定义两个函数。 第一个函数打印模块文档字符串。 第二个返回模块的路径。 函数可能会或可能不会返回值。 如果函数没有返回值，则它隐式返回`None`。 `__doc__`和`__file__`是特殊的状态属性。 请注意，属性的两侧都有两个下划线。

```py
$ ./ret.py

The ret.py script shows how to work with
functions in Python.
Author: Jan Bodnar
ZetCode, 2019

None C:/Users/Jano/PycharmProjects/Simple/simple.py

```

这是程序的输出。

函数的定义必须先于其用法。 否则，口译员会抱怨`NameError`。

`func_prec.py`

```py
#!/usr/bin/env python

# func_prec.py

def f1():
    print("f1()")

f1()
#f2()

def f2():
    print("f2()")

```

在上面的示例中，我们有两个函数定义。 一行被注释。 函数调用不能超出其定义。

```py
#f2()

def f2():
    print("f2()")

```

仅在定义后才能调用`f2()`。 取消注释该行，我们得到一个`NameError`。

## 在哪里定义函数

可以在模块，类或其他函数中定义函数。 在类内部定义的函数称为方法。

`defining.py`

```py
#!/usr/bin/env python

# defining.py

class Some():

    @staticmethod
    def f():
        print("f() method")

def f():
    print("f() function")

def g():
    def f():
        print("f() inner function")
    f()

Some.f()
f()
g()

```

在此示例中，我们在三个不同的位置定义了`f()`函数。

```py
# defining.py

class Some():

    @staticmethod
    def f():
        print("f() method")

```

静态方法在`Some`类中用装饰器定义。

```py
def f():
    print("f() function")

```

该函数在模块中定义。

```py
def g():
    def f():
        print("f() inner function")
    f()

```

此处，`f()`函数在另一个`g()`函数内部定义。 这是一个内部函数。

```py
Some.f()
f()
g()

```

通过使用方括号指定类名称，点运算符和函数名称来调用静态方法。 其他函数使用其名称和方括号来调用。

```py
$ ./defining.py
f() method
f() function
f() inner function

```

这是输出。

## Python 函数是对象

Python 中的函数是对象。 它们可以像 Python 中的其他对象一样进行操作。 因此，职能被称为头等公民。 在其他 OOP 语言（例如 Java 或 C# ）中，情况并非如此。

`fun_obj.py`

```py
#!/usr/bin/env python

# fun_obj.py

def f():
    """This function prints a message """

    print("Today it is a cloudy day")

print(isinstance(f, object))
print(id(f))

print(f.__doc__)
print(f.__name__)

```

在此脚本中，我们表明我们的函数也是一个对象。

```py
def f():
    """This function prints a message """

    print("Today it is a cloudy day")

```

我们定义一个`f()`函数。 它将消息打印到控制台。 它还具有一个文档字符串。

```py
print(isinstance(f, object))

```

`isinstance()`函数检查`f()`函数是否是`object`的实例。 Python 中的所有对象均从该基本实体继承。

```py
print(id(f))

```

Python 中的每个对象都有一个唯一的 ID。 `id()`函数返回对象的 ID。

```py
print(f.__doc__)
print(f.__name__)

```

对象可能具有属性； 我们打印函数的两个属性：`__doc__`和`__name__`。

```py
$ ./fun_obj.py
True
140353774014536
This function prints a message
f

```

这是程序的输出。

函数可以存储在集合中并传递给其他函数。

`fun_coll.py`

```py
#!/usr/bin/env python

# fun_coll.py

def f():
    pass

def g():
    pass

def h(f):
    print(id(f))

a = (f, g, h)

for i in a:
    print(i)

h(f)
h(g)

```

我们定义了三个函数。 我们将它们放在一个元组中，然后将它们传递给函数。

```py
a = (f, g, h)

for i in a:
    print(i)

```

我们将三个函数对象放在一个元组中，并使用`for`循环遍历它。

```py
h(f)
h(g)

```

我们将`f()`和`g()`函数传递给`h()`函数。

```py
$ ./fun_coll.py
<function f at 0x0000015B998E9D08>
<function g at 0x0000015B998E9E18>
<function h at 0x0000015B998E9840>
1492929912072
1492929912344

```

这是`fun_coll.py`程序的输出。

## Python 中的三种函数

从特定的角度来看，我们可以辨别出三种函数。 始终可供使用的函数，必须导入的外部模块中包含的函数以及由程序员使用`def`关键字定义的函数。

`three_kinds.py`

```py
#!/usr/bin/env python

from math import sqrt

def cube(x):
    return x * x * x

print(abs(-1))
print(cube(9))
print(sqrt(81))

```

上面的代码中存在三种函数。

```py
from math import sqrt

```

`sqrt()`函数是从数学模块导入的。

```py
def cube(x):
    return x * x * x

```

`cube()`函数是一个自定义函数。

```py
print(abs(-1))

```

`abs()`函数是易于访问的内置函数。 它是语言核心的一部分。

## Python `return`关键字

创建一个函数来执行特定任务。 通常，这种任务会产生结果。 `return`关键字用于从函数返回值。 函数可能会也可能不会返回值。 如果一个函数没有`return`关键字，它将发送`None`。

`returning.py`

```py
#!/usr/bin/env python

# returning.py

def show_message(msg):
    print(msg)

def cube(x):
    return x * x * x

x = cube(3)
print(x)

show_message("Computation finished.")
print(show_message("Ready."))

```

我们定义了两个函数。 一个使用`return`关键字，另一个则不使用。

```py
def show_message(msg):
    print(msg)

```

`show_message()`函数不会显式返回值。 它在控制台上显示一条消息。

```py
def cube(x):
    return x * x * x

```

`cube()`函数计算一个表达式，并使用`return`关键字返回其结果。

```py
x = cube(3)

```

在这一行中，我们称为`cube()`函数。 返回`cube()`函数的计算结果，并将其分配给`x`变量。 现在保存结果值。

```py
show_message("Computation finished.")

```

我们以消息为参数调用`show_message()`函数。 该消息将打印到控制台。 我们不期望此函数有值。

```py
print(show_message("Ready."))

```

此代码产生两行。 一种是通过`show_message()`函数打印的消息。 另一个是`None`值，该值由没有`return`语句的函数隐式发送。

```py
$ ./returning.py
27
Computation finished.
Ready.
None

```

这是示例输出。

我们可以从函数中发送多个值。 `return`关键字之后的对象用逗号分隔。

`returning2.py`

```py
#!/usr/bin/env python

# returning2.py

n = [1, 2, 3, 4, 5]

def stats(x):

    _mx = max(x)
    _mn = min(x)
    _ln = len(x)
    _sm = sum(x)

    return _mx, _mn, _ln, _sm

mx, mn, ln, sm = stats(n)
print(stats(n))

print(mx, mn, ln, sm)

```

有`stats()`函数的定义。 此函数返回四个值。

```py
return _mx, _mn, _ln, _sm

```

`return`关键字发回四个数字。 这些数字用逗号分隔。 实际上，我们已经发送了包含这四个值的元组。 我们也可以返回列表而不是元组。

```py
mx, mn, ln, sm = stats(n)

```

返回的值分配给局部变量。

```py
$ ./returning2.py
(5, 1, 5, 15)
5 1 5 15

```

这是输出。

## Python 函数重新定义

Python 本质上是动态的。 可以重新定义已经定义的函数。

`redefinition.py`

```py
#!/usr/bin/env python

# redefinition.py

from time import gmtime, strftime

def show_message(msg):
    print(msg)

show_message("Ready.")

def show_message(msg):
    print(strftime("%H:%M:%S", gmtime()))
    print(msg)

show_message("Processing.")

```

我们定义一个`show_message()`函数。 稍后，我们提供相同函数的新定义。

```py
from time import gmtime, strftime

```

从时间模块中，我们导入两个函数，用于计算当前时间。

```py
def show_message(msg):
    print(msg)

```

这是函数的第一个定义。 它仅将消息打印到控制台。

```py
def show_message(msg):
    print(strftime("%H:%M:%S", gmtime()))
    print(msg)

```

在源代码的后面，我们设置了`showMessage()`函数的新定义。 该消息之前带有时间戳。

```py
$ ./redefinition.py
Ready.
23:49:33 Processing.

```

这是输出。

## Python 函数参数

大多数函数接受参数。 参数是发送到函数的值。 这些函数处理这些值并有选择地返回一些值。

`fahrenheit.py`

```py
#!/usr/bin/env python

# fahrenheit.py

def C2F(c):
    return c * 9/5 + 32

print(C2F(100))
print(C2F(0))
print(C2F(30))

```

在我们的示例中，我们将摄氏温度转换为华氏温度。 `C2F()`函数接受一个参数`c`，即摄氏温度。

```py
$ ./fahrenheit.py
212
32
86

```

Python 函数中的参数可能具有隐式值。 如果未提供任何值，则使用隐式值。

`fun_implicit.py`

```py
#!/usr/bin/env python

# fun_implicit.py

def power(x, y=2):

    r = 1

    for i in range(y):
        r = r * x

    return r

print(power(3))
print(power(3, 3))
print(power(5, 5))

```

在这里，我们创建了幂函数。 该函数有一个带有隐式值的参数。 我们可以使用一个或两个参数来调用该函数。

```py
$ ./fun_implicit.py
9
27
3125

```

Python 函数可以使用关键字指定其参数。 这意味着在调用函数时，我们同时指定了关键字和值。 当我们有多个参数并且不使用关键字而使用它们时，传递这些参数的顺序至关重要。 如果我们期望在没有关键字的函数中使用名称，年龄或性别，则无法更改其顺序。 如果使用关键字，我们可以。

`fun_keywords.py`

```py
#!/usr/bin/env python

# fun_keywords.py

def display(name, age, sex):

    print("Name: ", name)
    print("Age: ", age)
    print("Sex: ", sex)

display("Lary", 43, "M")
display("Joan", 24, "F")

```

在此示例中，我们指定参数的顺序很重要。 否则，我们将得到错误的结果。

```py
$ ./fun_keywords.py
Name:  Lary
Age:  43
Sex:  M
Name:  Joan
Age:  24
Sex:  F

```

`fun_keywords2.py`

```py
#!/usr/bin/env python

# fun_keywords2.py

def display(name, age, sex):

    print("Name: ", name)
    print("Age: ", age)
    print("Sex: ", sex)

display(age=43, name="Lary", sex="M")
display(name="Joan", age=24, sex="F")

```

现在我们用它们的关键字来调用函数。 可以更改顺序，尽管不建议这样做。 请注意，我们不能在关键字参数之后使用非关键字参数。 这将导致语法错误。

```py
display("Joan", sex="F", age=24)

```

这是法律构想。 非关键字参数后可以跟关键字参数。

```py
display(age=24, name="Joan", "F")

```

这将导致语法错误。 非关键字参数不能跟在关键字参数之后。

Python 中的函数可以接受任意数量的参数。

`arbitrary_args.py`

```py
#!/usr/bin/env python

# arbitrary_args.py

def do_sum(*args):
    """Function returns the sum
of all values"""

    r = 0

    for i in args:
        r += i

    return r

print(do_sum.__doc__)
print(do_sum(1, 2, 3))
print(do_sum(1, 2, 3, 4, 5))

```

我们使用`*`运算符表示该函数接受任意数量的参数。 `do_sum()`函数返回所有参数的总和。 函数主体中的第一个字符串称为函数文档字符串。 用于记录函数。 该字符串必须用三引号引起来。

```py
$ ./arbitrary_args.py
Function returns the sum
of all values
6
15

```

我们还可以在函数中使用`**`构造。 在这种情况下，该函数将接受字典。 字典有任意长度。 然后，我们通常可以照常解析字典。

`details.py`

```py
#!/usr/bin/env python

# details.py

def display(**details):

    for i in details:
        print(f"{i}: {details[i]}")

display(name="Larry", age=43, sex="M")

```

本示例说明了这种情况。 我们可以提供任意数量的键值参数。 该函数将处理所有这些。

```py
$ ./details.py
age: 43
name: Larry
sex: M

```

## Python 通过引用传递参数

函数的参数通过引用传递。 一些语言将对象的副本传递给函数。 通过引用传递对象有两个重要结论：a）与传递对象副本相比，此过程更快。 b）在函数中修改的可变对象将永久更改。

`passing_by_reference.py`

```py
#!/usr/bin/env python

# passing_by_reference.py

n = [1, 2, 3, 4, 5]

print("Original list:", n)

def f(x):

    x.pop()
    x.pop()
    x.insert(0, 0)
    print("Inside f():", x)

f(n)

print("After function call:", n)

```

在我们的示例中，我们将整数列表传递给函数。 该对象在函数体内被修改。 调用该函数（原始对象）后，将修改整数列表。

```py
def f(x):

    x.pop()
    x.pop()
    x.insert(0, 0)
    print("Inside f():", x)

```

在函数主体中，我们使用原始对象。 不带对象的副本。 在许多编程语言中，默认情况下，我们将收到对象的副本。

```py
$ ./passing_by_reference.py
Original list: [1, 2, 3, 4, 5]
Inside f(): [0, 1, 2, 3]
After function call: [0, 1, 2, 3]

```

一旦列表被修改，它就被永久修改了。

## Python 全局和局部变量

接下来，我们将讨论如何在 Python 函数中使用变量。

`local_variable.py`

```py
#!/usr/bin/env python

# local_variable.py

name = "Jack"

def f():
    name = "Robert"
    print("Within function", name)

print("Outside function", name)
f()

```

在函数体中定义的变量具有局部范围。 它仅在函数体内有效。

```py
$ ./local_variable.py
Outside function Jack
Within function Robert

```

这是示例输出。

`global_variable.py`

```py
#!/usr/bin/env python

# global_variable.py

name = "Jack"

def f():
    print("Within function", name)

print("Outside function", name)
f()

```

默认情况下，我们可以在函数体内获取全局变量的内容。

```py
$ ./global_variable.py
Outside function Jack
Within function Jack

```

但是，如果要更改函数中的全局变量，则必须使用`global`关键字。

`global_variable2.py`

```py
#!/usr/bin/env python

# global_variable2.py

name = "Jack"

def f():

    global name
    name = "Robert"
    print("Within function", name)

print("Outside function", name)
f()
print("Outside function", name)

```

现在，我们将在函数内部更改全局名称变量的内容。

```py
global name
name = "Robert"

```

使用`global`关键字，我们引用在函数主体外部定义的变量。 该变量被赋予一个新值。

```py
$ ./global_variable2.py
Outside function Jack
Within function Robert
Outside function Robert

```

## Python 匿名函数

可以在 Python 中创建匿名函数。 匿名函数没有名称。 使用`lambda`关键字，几乎无法创建任何匿名函数。 Python 程序员也将匿名函数称为 lambda 函数。 它们是 Python 中合并的函数示例的一部分。

Lambda 函数仅限于单个表达式。 它们可以在可以使用常规函数的任何地方使用。 ZetCode 上有一个 [Python lambda 函数](http://zetcode.com/python/lambda/)教程。

`lambda_fun.py`

```py
#!/usr/bin/env python

# lambda_fun.py

y = 6

z = lambda x: x * y
print(z(8))

```

这是 lambda 函数的一个小例子。

```py
z = lambda x: x * y

```

`lambda`关键字创建一个匿名函数。 `x`是传递给 lambda 函数的参数。 参数后跟一个冒号。 冒号旁边的代码是在调用 lambda 函数时执行的表达式。 lambda 函数被分配给`z`变量。

```py
print(z(8))

```

lambda 函数被执行。 数字 8 传递给匿名函数，结果返回 48。 请注意，`z`不是此函数的名称。 它只是分配了匿名函数的变量。

```py
$ ./lambda_fun.py
48

```

这是示例的输出。

lambda 函数可以与`map()`或`filter()`函数之类的 Python 语言的其他函数部件完美地结合使用。

`lambda_fun2.py`

```py
#!/usr/bin/env python

# lambda_fun2.py

cs = [-10, 0, 15, 30, 40]

ft = map(lambda t: (9.0/5)*t + 32, cs)
print(list(ft))

```

在示例中，我们列出了摄氏温度。 我们创建一个包含华氏温度的新列表。

```py
ft = map(lambda t: (9.0/5)*t + 32, cs)

```

`map()`函数将匿名函数应用于`cs`列表的每个元素。 它返回计算出的华氏温度的可迭代值。

```py
$ ./lambda_fun2.py
[14.0, 32.0, 59.0, 86.0, 104.0]

```

这是示例输出。

本章是关于 Python 中的函数的。