跳转至

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

1
2
3
4
5
6
7
8
$ ./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()")

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

1
2
3
4
#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()函数。

1
2
3
4
5
6
7
# defining.py

class Some():

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

静态方法在Some类中用装饰器定义。

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

该函数在模块中定义。

1
2
3
4
def g():
    def f():
        print("f() inner function")
    f()

此处,f()函数在另一个g()函数内部定义。 这是一个内部函数。

1
2
3
Some.f()
f()
g()

通过使用方括号指定类名称,点运算符和函数名称来调用静态方法。 其他函数使用其名称和方括号来调用。

1
2
3
4
$ ./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__)

在此脚本中,我们表明我们的函数也是一个对象。

1
2
3
4
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__

1
2
3
4
5
$ ./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)

我们定义了三个函数。 我们将它们放在一个元组中,然后将它们传递给函数。

1
2
3
4
a = (f, g, h)

for i in a:
    print(i)

我们将三个函数对象放在一个元组中,并使用 for 循环遍历它。

h(f)
h(g)

我们将f()g()函数传递给h()函数。

1
2
3
4
5
6
$ ./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语句的函数隐式发送。

1
2
3
4
5
$ ./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)

返回的值分配给局部变量。

1
2
3
$ ./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)

这是函数的第一个定义。 它仅将消息打印到控制台。

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

在源代码的后面,我们设置了showMessage()函数的新定义。 该消息之前带有时间戳。

1
2
3
$ ./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,即摄氏温度。

1
2
3
4
$ ./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))

在这里,我们创建了幂函数。 该函数有一个带有隐式值的参数。 我们可以使用一个或两个参数来调用该函数。

1
2
3
4
$ ./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")

在此示例中,我们指定参数的顺序很重要。 否则,我们将得到错误的结果。

1
2
3
4
5
6
7
$ ./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()函数返回所有参数的总和。 函数主体中的第一个字符串称为函数文档字符串。 用于记录函数。 该字符串必须用三引号引起来。

1
2
3
4
5
$ ./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")

本示例说明了这种情况,我们可以提供任意数量的键值参数,该函数将处理所有这些。

1
2
3
4
$ ./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)

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

1
2
3
4
5
6
def f(x):

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

在函数主体中,我们使用原始对象,不带对象的副本。 在许多编程语言中,默认情况下,我们将收到对象的副本。

1
2
3
4
$ ./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()

在函数体中定义的变量具有局部范围。 它仅在函数体内有效。

1
2
3
$ ./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()

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

1
2
3
$ ./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关键字,我们引用在函数主体外部定义的变量。 该变量被赋予一个新值。

1
2
3
4
$ ./global_variable2.py
Outside function Jack
Within function Robert
Outside function Robert

Python 匿名函数

可以在 Python 中创建匿名函数。 匿名函数没有名称。 使用lambda关键字,几乎无法创建任何匿名函数。 Python 程序员也将匿名函数称为 lambda 函数。 它们是 Python 中合并的函数示例的一部分。

Lambda 函数仅限于单个表达式。 它们可以在可以使用常规函数的任何地方使用。

lambda_fun.py
1
2
3
4
5
6
7
8
#!/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
1
2
3
4
5
6
7
8
#!/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]