在本文中,我们介绍了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, 2022 """ 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, 2022 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 # 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()
通过在方括号中指定类名、dotoperator和函数名来调用静态方法。其他函数使用它们的名称和方括号调用。
$ ./defining.py f() method f() function f() inner function
Python函数是对象
Python中的函数是对象。它们可以像Python中的其他对象一样被操作。因此函数被称为一等公民。这在其他OOP语言(如Java或C#)中并非如此。
#!/usr/bin/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
函数是否是对象
的实例。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
关键字用于从函数返回值。函数可能会返回值,也可能不会返回值。如果函数没有返回关键字,它将发送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
我们从时间模块导入了两个用于计算当前时间的函数。
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 # 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函数中的参数可能具有隐式值。如果未提供值,则使用隐式值。
#!/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 # 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
#!/usr/bin/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中的函数可以接受任意数量的参数。
#!/usr/bin/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
我们还可以在我们的函数中使用**
结构。在这种情况下,该函数将接受字典。字典有任意长度。然后我们可以像往常一样正常解析字典。
#!/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
Python通过引用传递参数
函数的参数通过引用传递。一些语言将对象的副本传递给函数。通过引用传递对象有两个重要结论:a)过程比传递对象副本更快;b)可变对象是函数中的修改将永久更改。
#!/usr/bin/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函数中是如何使用的。
#!/usr/bin/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
#!/usr/bin/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
关键字。
#!/usr/bin/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上有一个Pythonlambda函数教程。
#!/usr/bin/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函数可以优雅地与Python语言的其他功能部分一起使用,例如map
或filter
函数。
#!/usr/bin/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函数。
列出所有Python教程。