Python 函数
最后修改于 2024 年 1 月 29 日
在本文中,我们将介绍 Python 中的函数。
Python 函数定义
函数是将零个或多个输入参数映射到零个或多个输出参数。
使用函数的好处是
- 代码组织
- 减少代码重复
- 将复杂问题分解为更简单的部分
- 提高代码清晰度
- 代码重用
- 信息隐藏
Python 中的函数是“一等公民”。这意味着函数在 Python 中与其他对象具有相同的地位。函数可以赋值给变量、存储在集合中或作为参数传递。这为语言带来了额外的灵活性。
Python 函数类型
有两种基本类型的函数:内置函数和用户定义函数。内置函数是 Python 语言的一部分;例如 dir
、len
或 abs
。用户定义函数是使用 def
关键字创建的函数。
Python 创建函数
函数使用 def
关键字创建。函数块中的语句必须缩进。
def function(): pass
def
关键字后面是带有圆括号的函数名和一个冒号。缩进的语句构成函数的主体。
函数稍后会在需要时执行。我们说我们调用函数。如果我们调用一个函数,函数主体内的语句将被执行。它们直到函数被调用才会被执行。
myfunc()
要调用函数,我们指定带有圆括号的函数名。
#!/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
。
#!/usr/bin/python # func_prec.py def f1(): print("f1()") f1() #f2() def f2(): print("f2()")
在上面的示例中,我们有两个函数定义。一行被注释掉了。函数调用不能在其定义之前。
#f2() def f2(): print("f2()")
我们只能在其定义之后调用 f2
。取消注释该行,我们会得到一个 NameError
。
在哪里定义函数
函数可以在模块、类或函数内部定义。在类内部定义的函数称为成员函数或方法。
#!/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 语言中并非如此。
#!/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
函数可以存储在集合中并传递给其他函数。
#!/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)
我们将 f
和 g
函数传递给 h
函数。
$ ./fun_coll.py <function f at 0x0000015B998E9D08> <function g at 0x0000015B998E9E18> <function h at 0x0000015B998E9840> 1492929912072 1492929912344
Python 中的三种函数
从特定角度来看,我们可以区分三种函数:始终可用的函数、包含在外部模块中(必须导入)的函数以及使用 def
关键字由程序员定义的函数。
#!/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
。
#!/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
关键字后的对象由逗号分隔。
#!/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 本质上是动态的。可以重新定义一个已定义的函数。
#!/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 函数参数
大多数函数都接受参数。参数是发送到函数的值。函数处理这些值并可选地返回某些值。
#!/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 函数中的参数可以有默认值。如果没有提供值,则使用默认值。
#!/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 函数可以使用关键字指定其参数。这意味着在调用函数时,我们同时指定关键字和值。当有多个参数且不使用关键字传递它们时,传递参数的顺序至关重要。如果我们期望函数接收一个名字、年龄或性别但没有关键字,我们不能改变它们的顺序。如果我们使用关键字,我们就可以。
#!/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
#!/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 中的函数可以接受任意数量的参数。
#!/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
我们还可以在函数中使用 **
构造。在这种情况下,函数将接受一个字典。字典的长度是任意的。然后我们可以像往常一样正常解析字典。
#!/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
解包函数返回值
解包是将对象(如列表)分解为其元素。它也称为解构。_ 运算符用于忽略该值。* 运算符会贪婪地获取所有元素直到下一个参数。
#!/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
变量获取前三个值。其余值被解包到 b
、c
和 d
变量中。
$ ./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
解包函数参数
我们可以将值解包到函数参数中。
#!/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) 在函数中修改的可变对象会被永久更改。
#!/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 函数中的用法。
#!/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
#!/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
关键字。
#!/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 函数的教程。
#!/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 语言的函数部分结合使用,例如 map
或 filter
函数。
#!/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 教程。