Python 函数
Python 函数 是用于执行特定操作的可重用代码块。 使用函数的优点是:
- 减少代码重复
- 将复杂的问题分解成更简单的部分
- 提高代码的清晰度
- 重用代码
- 信息隐藏
Python 中的函数是一等公民。 这意味着函数与 Python 中的其他对象具有同等的状态。 可以将函数分配给变量,存储在集合中或作为参数传递,这给语言带来了额外的灵活性。
Python 函数类型
函数有两种基本类型:内置函数和用户定义函数。 内置函数是 Python 语言的一部分; 例如dir()
,len()
或abs()
。 用户定义的函数是使用def
关键字创建的函数。
Python 创建函数
使用def
关键字创建一个函数。 函数块中的语句必须缩进。
def
关键字后跟带有圆括号和冒号的函数名称。 缩进语句形成函数的主体。
该函数稍后在需要时执行。 我们说我们调用函数。 如果我们调用一个函数,则会执行函数体内的语句。 在调用函数之前,它们不会执行。
要调用函数,我们用圆括号指定函数名称。
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()
函数内部定义。 这是一个内部函数。
通过使用方括号指定类名称,点运算符和函数名称来调用静态方法。 其他函数使用其名称和方括号来调用。
| $ ./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 中的所有对象均从该基本实体继承。
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 循环遍历它。
我们将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))
|
上面的代码中存在三种函数。
sqrt()
函数是从数学模块导入的。
| def cube(x):
return x * x * x
|
cube()函数是一个自定义函数。
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
关键字返回其结果。
在这一行中,我们称为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 函数仅限于单个表达式。 它们可以在可以使用常规函数的任何地方使用。
lambda_fun.py
| #!/usr/bin/env python
# lambda_fun.py
y = 6
z = lambda x: x * y
print(z(8))
|
这是 lambda 函数的一个小例子。
lambda
关键字创建一个匿名函数。 x
是传递给 lambda 函数的参数。 参数后跟一个冒号。 冒号旁边的代码是在调用 lambda 函数时执行的表达式。 lambda 函数被分配给z
变量。
lambda 函数被执行。 数字 8 传递给匿名函数,结果返回 48。 请注意,z
不是此函数的名称。 它只是分配了匿名函数的变量。
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]
|