在 Python 编程教程的这一部分中,我们介绍了 Python 中的函数。
Python 函数定义
函数是用于执行特定操作的可重用代码块。 使用函数的优点是:
- 减少代码重复
- 将复杂的问题分解成更简单的部分
- 提高代码的清晰度
- 重用代码
- 信息隐藏
Python 中的函数是一等公民。 这意味着函数与 Python 中的其他对象具有同等的状态。 可以将函数分配给变量,存储在集合中或作为参数传递。 这给语言带来了额外的灵活性。
Python 函数类型
函数有两种基本类型:内置函数和用户定义函数。 内置函数是 Python 语言的一部分; 例如dir()
,len()
或abs()
。 用户定义的函数是使用def
关键字创建的函数。
Python 创建函数
使用def
关键字创建一个函数。 函数块中的语句必须缩进。
def function():
pass
def
关键字后跟带有圆括号和冒号的函数名称。 缩进语句形成函数的主体。
该函数稍后在需要时执行。 我们说我们调用函数。 如果我们调用一个函数,则会执行函数体内的语句。 在调用函数之前,它们不会执行。
myfunc()
要调用函数,我们用圆括号指定函数名称。
ret.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__
是特殊的状态属性。 请注意,属性的两侧都有两个下划线。
$ ./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
#!/usr/bin/env 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/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()
函数。
# defining.py
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()
函数内部定义。 这是一个内部函数。
Some.f()
f()
g()
通过使用方括号指定类名称,点运算符和函数名称来调用静态方法。 其他函数使用其名称和方括号来调用。
$ ./defining.py
f() method
f() function
f() inner function
这是输出。
Python 函数是对象
Python 中的函数是对象。 它们可以像 Python 中的其他对象一样进行操作。 因此,职能被称为头等公民。 在其他 OOP 语言(例如 Java 或 C# )中,情况并非如此。
fun_obj.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__)
在此脚本中,我们表明我们的函数也是一个对象。
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/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)
我们定义了三个函数。 我们将它们放在一个元组中,然后将它们传递给函数。
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
这是fun_coll.py
程序的输出。
Python 中的三种函数
从特定的角度来看,我们可以辨别出三种函数。 始终可供使用的函数,必须导入的外部模块中包含的函数以及由程序员使用def
关键字定义的函数。
three_kinds.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))
上面的代码中存在三种函数。
from math import sqrt
sqrt()
函数是从数学模块导入的。
def cube(x):
return x * x * x
cube()
函数是一个自定义函数。
print(abs(-1))
abs()
函数是易于访问的内置函数。 它是语言核心的一部分。
Python return
关键字
创建一个函数来执行特定任务。 通常,这种任务会产生结果。 return
关键字用于从函数返回值。 函数可能会也可能不会返回值。 如果一个函数没有return
关键字,它将发送None
。
returning.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
关键字,另一个则不使用。
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/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()
函数的定义。 此函数返回四个值。
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/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()
函数。 稍后,我们提供相同函数的新定义。
from time import gmtime, strftime
从时间模块中,我们导入两个函数,用于计算当前时间。
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/env python
# fahrenheit.py
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/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))
在这里,我们创建了幂函数。 该函数有一个带有隐式值的参数。 我们可以使用一个或两个参数来调用该函数。
$ ./fun_implicit.py
9
27
3125
Python 函数可以使用关键字指定其参数。 这意味着在调用函数时,我们同时指定了关键字和值。 当我们有多个参数并且不使用关键字而使用它们时,传递这些参数的顺序至关重要。 如果我们期望在没有关键字的函数中使用名称,年龄或性别,则无法更改其顺序。 如果使用关键字,我们可以。
fun_keywords.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")
在此示例中,我们指定参数的顺序很重要。 否则,我们将得到错误的结果。
$ ./fun_keywords.py
Name: Lary
Age: 43
Sex: M
Name: Joan
Age: 24
Sex: F
fun_keywords2.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")
现在我们用它们的关键字来调用函数。 可以更改顺序,尽管不建议这样做。 请注意,我们不能在关键字参数之后使用非关键字参数。 这将导致语法错误。
display("Joan", sex="F", age=24)
这是法律构想。 非关键字参数后可以跟关键字参数。
display(age=24, name="Joan", "F")
这将导致语法错误。 非关键字参数不能跟在关键字参数之后。
Python 中的函数可以接受任意数量的参数。
arbitrary_args.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()
函数返回所有参数的总和。 函数主体中的第一个字符串称为函数文档字符串。 用于记录函数。 该字符串必须用三引号引起来。
$ ./arbitrary_args.py
Function returns the sum
of all values
6
15
我们还可以在函数中使用**
构造。 在这种情况下,该函数将接受字典。 字典有任意长度。 然后,我们通常可以照常解析字典。
details.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")
本示例说明了这种情况。 我们可以提供任意数量的键值参数。 该函数将处理所有这些。
$ ./details.py
age: 43
name: Larry
sex: M
Python 通过引用传递参数
函数的参数通过引用传递。 一些语言将对象的副本传递给函数。 通过引用传递对象有两个重要结论:a)与传递对象副本相比,此过程更快。 b)在函数中修改的可变对象将永久更改。
passing_by_reference.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)
在我们的示例中,我们将整数列表传递给函数。 该对象在函数体内被修改。 调用该函数(原始对象)后,将修改整数列表。
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/env python
# local_variable.py
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/env python
# global_variable.py
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/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)
现在,我们将在函数内部更改全局名称变量的内容。
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/env python
# lambda_fun.py
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 函数可以与map()
或filter()
函数之类的 Python 语言的其他函数部件完美地结合使用。
lambda_fun2.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))
在示例中,我们列出了摄氏温度。 我们创建一个包含华氏温度的新列表。
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 中的函数的。