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 教程。