ZetCode

Python 函数

最后修改于 2024 年 1 月 29 日

在本文中,我们将介绍 Python 中的函数。

Python 函数定义

函数是将零个或多个输入参数映射到零个或多个输出参数。

使用函数的好处是

Python 中的函数是“一等公民”。这意味着函数在 Python 中与其他对象具有相同的地位。函数可以赋值给变量、存储在集合中或作为参数传递。这为语言带来了额外的灵活性。

Python 函数类型

有两种基本类型的函数:内置函数和用户定义函数。内置函数是 Python 语言的一部分;例如 dirlenabs。用户定义函数是使用 def 关键字创建的函数。

Python 创建函数

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

def function():
    pass

def 关键字后面是带有圆括号的函数名和一个冒号。缩进的语句构成函数的主体

函数稍后会在需要时执行。我们说我们调用函数。如果我们调用一个函数,函数主体内的语句将被执行。它们直到函数被调用才会被执行。

myfunc()

要调用函数,我们指定带有圆括号的函数名。

ret.py
#!/usr/bin/python

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


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__ 是特殊的状态属性。请注意,属性两边都有两个下划线。

$ ./ret.py

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

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

函数定义必须在其使用之前。否则,解释器会抱怨 NameError

func_prec.py
#!/usr/bin/python

# func_prec.py


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


f1()
#f2()


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

在上面的示例中,我们有两个函数定义。一行被注释掉了。函数调用不能在其定义之前。

#f2()


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

我们只能在其定义之后调用 f2。取消注释该行,我们会得到一个 NameError

在哪里定义函数

函数可以在模块、类或函数内部定义。在类内部定义的函数称为成员函数方法

defining.py
#!/usr/bin/python

class Info:

    def say(self):
        print('This is Info class')

class Some:

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

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

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


i = Info()
i.say()

Some.f()
f()
g()

在此示例中,我们在不同位置定义了一个 f 函数。

class Info:

    def say(self):
        print('This is Info class')

我们定义了一个成员函数。该函数在对象实例上调用。

class Some:

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

静态方法使用 Some 类中的装饰器定义。该方法在类名上调用。

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

该函数在模块中定义。它是一个普通函数。

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

这里 f 函数定义在另一个 g 函数内部。它是一个内部函数。

i = Info()
i.say()

我们创建了一个 Info 类的实例。我们使用点运算符在实例上调用 say 方法。

Some.f()

静态方法通过指定类名、点运算符和带方括号的函数名来调用。

f()
g()

普通函数使用其名称和圆括号调用。

$ ./defining.py
This is Info class
f() static method
f() plain function
f() inner function

Python 函数是对象

Python 中的函数是对象。它们可以像 Python 中的其他对象一样被操作。因此,函数被称为一等公民。这在 Java 或 C# 等其他 OOP 语言中并非如此。

fun_obj.py
#!/usr/bin/python

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__)

在此脚本中,我们展示了我们的函数也是一个对象。

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

    print("Today it is a cloudy day")

我们定义了一个 f 函数。它向控制台打印一条消息。它还有一个文档字符串。

print(isinstance(f, object))

isinstance 函数检查 f 函数是否是 object 的实例。Python 中的所有对象都继承自这个基本实体。

print(id(f))

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

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

对象可能具有属性;我们打印了函数的两个属性:__doc____name__

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

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

fun_coll.py
#!/usr/bin/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)

我们定义了三个函数。我们将它们放入一个元组中并将其传递给一个函数。

a = (f, g, h)

for i in a:
    print(i)

我们将三个函数对象放入一个元组中,并通过 for 循环遍历它。

h(f)
h(g)

我们将 fg 函数传递给 h 函数。

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

Python 中的三种函数

从特定角度来看,我们可以区分三种函数:始终可用的函数、包含在外部模块中(必须导入)的函数以及使用 def 关键字由程序员定义的函数。

three_kinds.py
#!/usr/bin/python

from math import sqrt


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


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

上述代码中存在三种函数。

from math import sqrt

sqrt 函数从 math 模块导入。

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

cube() 函数是自定义定义的函数。

print(abs(-1))

abs 函数是一个内置函数,可立即访问。它是语言核心的一部分。

Python return 关键字

创建函数是为了执行特定任务。这类任务通常会产生一个结果。return 关键字用于从函数返回。函数可以返回值,也可以不返回值。如果没有 return 关键字,函数将发送 None

returning.py
#!/usr/bin/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 关键字,另一个则不使用。

def show_message(msg):
    print(msg)

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

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

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

x = cube(3)

在这行中,我们调用 cube 函数。cube 函数的计算结果被返回并赋值给 x 变量。它现在保存结果值。

show_message("Computation finished.")

我们调用 show_message 函数,并将一条消息作为参数。消息会打印到控制台。我们不期望此函数返回任何值。

print(show_message("Ready."))

此代码产生两行。一行是由 show_message 函数打印的消息。另一行是 None 值,它由没有 return 语句的函数隐式发送。

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

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

returning2.py
#!/usr/bin/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 函数的定义。该函数返回四个值。

return _mx, _mn, _ln, _sm

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

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

返回的值被赋值给局部变量。

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

Python 函数重定义

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

redefinition.py
#!/usr/bin/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 函数。稍后我们提供了该函数的新定义。

from time import gmtime, strftime

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

def show_message(msg):
    print(msg)

这是函数的第一定义。它只在控制台打印一条消息。

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

稍后在源代码中,我们设置了 showMessage 函数的新定义。消息前面加上了时间戳。

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

Python 函数参数

大多数函数都接受参数。参数是发送到函数的值。函数处理这些值并可选地返回某些值。

fahrenheit.py
#!/usr/bin/python

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


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

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

$ ./fahrenheit.py
212
32
86

Python 函数中的参数可以有默认值。如果没有提供值,则使用默认值。

fun_implicit.py
#!/usr/bin/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))

这里我们创建了一个幂函数。该函数有一个带有默认值的参数。我们可以用一个或两个参数调用该函数。

$ ./fun_implicit.py
9
27
3125

关键字函数参数

Python 函数可以使用关键字指定其参数。这意味着在调用函数时,我们同时指定关键字和值。当有多个参数且不使用关键字传递它们时,传递参数的顺序至关重要。如果我们期望函数接收一个名字、年龄或性别但没有关键字,我们不能改变它们的顺序。如果我们使用关键字,我们就可以。

fun_keywords.py
#!/usr/bin/python

def display(name, age, sex):

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


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

在此示例中,指定参数的顺序很重要。否则,我们会得到不正确的结果。

$ ./fun_keywords.py
Name:  Lary
Age:  43
Sex:  M
Name:  Joan
Age:  24
Sex:  F
fun_keywords2.py
#!/usr/bin/python

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")

现在我们使用关键字调用函数。可以改变顺序,但通常不建议这样做。请注意,不能在非关键字参数之后使用关键字参数。这会导致语法错误。这是一个合法的结构。非关键字参数可以后跟关键字参数。

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

这是一个合法的结构。非关键字参数可以后跟关键字参数。

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

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

任意数量的函数参数

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

arbitrary_args.py
#!/usr/bin/python


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 函数返回所有参数的总和。函数体中的第一个字符串称为函数文档字符串。它用于记录函数。字符串必须用三重引号括起来。

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

我们还可以在函数中使用 ** 构造。在这种情况下,函数将接受一个字典。字典的长度是任意的。然后我们可以像往常一样正常解析字典。

details.py
#!/usr/bin/python

# details.py


def display(**details):

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


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

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

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

解包函数返回值

解包是将对象(如列表)分解为其元素。它也称为解构。_ 运算符用于忽略该值。* 运算符会贪婪地获取所有元素直到下一个参数。

unpacking_return_values.py
#!/usr/bin/python

def fn():
    return [1, 2, 3, 4, 5, 6]

a, b, c, d, e, f = fn()
print(a, b, c, d, e, f)

a, *mid, b = fn()
print(a, mid, b)

a, b, c, _, _, _ = fn()
print(a, b, c)

a, b, c, *d = fn()
print(a, b, c, d)

*a, b, c, d = fn()
print(a, b, c, d)

我们有一个返回列表的函数。这些值被解包到单独的变量中。

a, b, c, d, e, f = fn()
print(a, b, c, d, e, f)

所有六个值都被解包到单独的六个变量中。

a, *mid, b = fn()
print(a, mid, b)

使用星号运算符,mid 变量获取除最后一个值之外的所有值。

a, b, c, _, _, _ = fn()
print(a, b, c)

我们使用 _ 运算符忽略最后三个值。

a, b, c, *d = fn()
print(a, b, c, d)

这里,d 变量获取所有剩余的值。它是一个列表。

*a, b, c, d = fn()
print(a, b, c, d)

a 变量获取前三个值。其余值被解包到 bcd 变量中。

$ ./unpacking.py
1 2 3 4 5 6
1 [2, 3, 4, 5] 6
1 2 3
1 2 3 [4, 5, 6]
[1, 2, 3] 4 5 6

解包函数参数

我们可以将值解包到函数参数中。

unpacking2.py
#!/usr/bin/python

def fn(a, b, c, d, e, f):
    print(a, b, c, d, e, f)

def fn2(a, b, c, *d):
    print(a, b, c, d)

def fn3(a, b, c, *d, e, f):
    print(a, b, c, d, e, f)

vals = [1, 2, 3, 4, 5, 6]

fn(*vals)
fn2(*vals)
fn3(*vals, e=7, f=8)

在示例中,我们将列表解包到函数参数中。

fn(*vals)

使用星号运算符,我们将列表元素解包到函数参数中。

def fn3(a, b, c, *d, e, f):
    print(a, b, c, d, e, f)
...
fn3(*vals, e=7, f=8)

由于 d 参数不是最后一个参数,我们需要为函数提供额外的关键字参数。

$ ./unpacking2.py
1 2 3 4 5 6
1 2 3 (4, 5, 6)
1 2 3 (4, 5, 6) 7 8

Python 按引用传递参数

函数参数是按引用传递的。有些语言将对象副本传递给函数。按引用传递对象有两个重要结论:a) 与传递对象副本相比,该过程更快;b) 在函数中修改的可变对象会被永久更改。

passing_by_reference.py
#!/usr/bin/python

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)

在我们的示例中,我们将一个整数列表传递给一个函数。该对象在函数体内部被修改。调用函数后,原始对象,即整数列表,会被修改。

def f(x):

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

在函数体内部,我们处理的是原始对象,而不是对象的副本。在许多编程语言中,我们默认会收到对象副本。

$ ./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
#!/usr/bin/python

name = "Jack"

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


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

在函数体中定义的变量具有局部作用域。它仅在函数体内部有效。

$ ./local_variable.py
Outside function Jack
Within function Robert
global_variable.py
#!/usr/bin/python

name = "Jack"

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


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

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

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

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

global_variable2.py
#!/usr/bin/python

name = "Jack"

def f():

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


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

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

global name
name = "Robert"

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

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

Python 匿名函数

可以在 Python 中创建匿名函数。匿名函数没有名称。使用 lambda 关键字,可以创建小的匿名函数。匿名函数也被 Python 程序员称为 lambda 函数。它们是 Python 中包含的函数式编程范例的一部分。

Lambda 函数仅限于单个表达式。它们可以在任何可以使用普通函数的地方使用。ZetCode 上有一个关于 Python lambda 函数的教程。

lambda_fun.py
#!/usr/bin/python

y = 6

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

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

z = lambda x: x * y

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

print(z(8))

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

$ ./lambda_fun.py
48

Lambda 函数可以优雅地与其他 Python 语言的函数部分结合使用,例如 mapfilter 函数。

lambda_fun2.py
#!/usr/bin/python

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

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

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

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

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

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

来源

Python 定义函数 - 语言参考

在本文中,我们涵盖了 Python 函数。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程