16 分钟阅读
了解 Python 函数的概念。如何创建用户定义的函数并使用它们在 Python 中编写模块化程序。
Python 中的函数是一个独立且可重用的代码块,您可以从程序中的任何位置调用任意次数。它是程序员将大项目拆分为较小模块的重要工具。
它们是程序员必须学会使用的任何编程语言的核心构建块。Python 提供了许多直接使用的内置方法,还允许您定义自定义函数。
-Python 中的函数是代码的逻辑单元,其中包含一系列语句,这些语句缩进到使用“def”关键字给出的名称下。
-函数允许您将大项目逻辑划分为较小的模块。它们使您的代码更易于管理和扩展。
- 编程时,功能可防止您添加重复代码并提高可重用性。
现在让我们快速看看我们还将从本教程中学到什么。
Python 函数的语法如下。
单线功能:
def single_line(): statement
带有帮助文档字符串的 Python 函数:
def fn(arg1, arg2,...): '''docstring''' statement1 statement2
嵌套的 Python 函数:
def fn(arg1, arg2,...): '''docstring''' statement1 statement2 def fn_new(arg1, arg2,...): statement1 statement2 ... ...
在创建第一个 Python 函数之前,请阅读以下说明。
例:
if test: def test(): # First definition ... else: def test(): # Alternate definition ... ...
通过使用 def 关键字,您学习了创建函数的蓝图,该函数具有名称、要传递的参数以及具有有效 Python 语句的主体。
下一步是执行它。您可以通过从 Python 脚本、函数内部或直接从 Python shell 调用它来实现。
要调用函数,您需要使用相关参数指定函数名称,仅此而已。
按照下面的示例学习如何在 Python 中调用函数。
这是一个简单的例子,其中函数“typeOfNum()”具有嵌套函数来决定数字是奇数还是偶数。
def typeOfNum(num): # Function header # Function body if num % 2 == 0: def message(): print('You entered an even number.') else: def message(): print('You entered an odd number.') message()# End of functiontypeOfNum(2) # call the functiontypeOfNum(3) # call the function again
例:
def product(x, y) : return x * yprint(product(4, 9)) # function returns 36print(product('Python!', 2)) # function returns # Python!Python!print(product('Python 2 or 3?', '3')) # TypeError occurs
上面的例子阐明了我们可以将任意两个对象传递给支持 '*' 运算符的 product() 函数。
我们上面解释的概念被称为多态性。您应该记住的一些要点如下。
我们经常互换使用术语参数和参数。但是,它们之间略有不同。
参数是函数定义中使用的变量,而参数是我们传递给函数参数的值。
Python 支持将参数传递给函数的不同变体。在我们讨论它们中的每一个之前,您应该阅读以下注释。
def test1(a, b) : a = 'Garbage' # 'a' receives an immutable object b[0] = 'Python' # 'b' receives a list object # list is mutable # it can undergo an in place changedef test2(a, b) : a = 'Garbage 2' b = 'Python 3' # 'b' now is made to refer to new # object and therefore argument 'y' # is not changedarg1 = 10arg2 = [1, 2, 3, 4]test1(arg1, arg2)print('After executing test 1 =>', arg1, arg2)test2(arg1, arg2)print('After executing test 2 =>', arg1, arg2)
执行后,上面的代码打印以下内容。
After executing test 1 => 10 ['Python', 2, 3, 4]After executing test 2 => 10 ['Python', 2, 3, 4]
def test1(a, b) : a = 'Garbage' b[0] = 'Python'arg1 = 10arg2 = [1, 2, 3, 4]print('Before test 1 =>', arg1, arg2)test1(arg1, arg2[:]) # Create an explicit copy of mutable object # 'y' in the function. # Now 'b' in test1() refers to a # different object which was initially a # copy of 'arg2' print('After test 1 =>', arg1, arg2)
执行后,上面的代码打印以下内容。
Before test 1 => 10 [1, 2, 3, 4]After test 1 => 10 [1, 2, 3, 4]
标准参数是按照 Python 函数定义中指定的方式传递的参数。这意味着无需更改其顺序,也无需跳过任何顺序。
def fn(value): print(value) returnfn()
执行上述代码会引发以下错误,因为我们尚未传递所需的单个参数。
TypeError: fn() missing 1 required positional argument: 'value'
当您为参数赋值(例如 param=value)并将其传递给函数(例如 fn(param=value))时,它会变成关键字参数。
如果将关键字参数传递给函数,则 Python 通过赋值中使用的参数名称来确定它。
def fn(value): print(value) returnfn(value=123) # output => 123fn(value='Python!') # output => Python!
使用关键字参数时,应确保赋值中的名称应与函数定义中的名称匹配。否则,Python 会抛出 TypeError,如下所示。
fn(value1='Python!') # wrong name used in the keyword argument
上述函数调用会导致以下错误。
TypeError: fn() got an unexpected keyword argument 'value1'
Python 函数允许在函数定义中设置参数的默认值。我们将它们称为默认参数。
当调用方未在函数调用中传递这些默认值时,被调用方使用这些默认值。
下面的示例将帮助您清楚地理解默认参数的概念。
def daysInYear(is_leap_year=False): if not is_leap_year: print('365 days') else: print('366 days') returndaysInYear()daysInYear(True)
在这里,参数“is_leap_year”用作默认参数。如果不传递任何值,则假定默认值为 False。
上述代码的输出为:
365 days366 days
您可能会遇到必须将其他参数传递给 Python 函数的情况。我们将它们称为可变长度参数。
Python 的 print() 本身就是支持动态参数的函数的一个例子。
要定义具有变量参数的函数,您需要在参数前面加上星号 (*)。请遵循以下语法。
def fn([std_args,] *var_args_tuple ): '''docstring''' function_body return_statement
查看以下示例以获得更好的清晰度。
def inventory(category, *items): print('%s [items=%d]:' % (category, len(items)), items) for item in items: print('-', item) returninventory('Electronics', 'tv', 'lcd', 'ac', 'refrigerator', 'heater')inventory('Books', 'python', 'java', 'c', 'c++')
上面代码的输出是这样的。
Electronics [items=5]: ('tv', 'lcd', 'ac', 'refrigerator', 'heater')- tv- lcd- ac- refrigerator- heaterBooks [items=4]: ('python', 'java', 'c', 'c++')- python- java- c- c++
请注意,您可以选择在函数定义中与可变参数一起使用或不具有正式参数。
您可以选择在调用函数时跳过可变参数。在这种情况下,元组将保持为空。
局部变量仅在代码块(如函数 def)内具有可见性。
它们仅在执行函数时可用。
查看下面的使用局部变量的示例。
def fn(a, b) : temp = 1 for iter in range(b) : temp = temp*a return tempprint(fn(2, 4))print(temp) # error : can not access 'temp' out of scope of function 'fn'print(iter) # error : can not access 'iter' out of scope of function 'fn'
在这个例子中,访问函数体外部的局部变量,这会导致 NameError。
函数的局部变量在调用之间不保留值。def 内部使用的名称不会与 def 外部的变量冲突,即使您在其他地方使用了相同的名称也是如此。
在 Python 中,变量赋值可以发生在三个不同的地方。
global 关键字是 Python 中的语句。它使变量(名称)能够保留位于模块文件顶层的 def 之外的更改。
在单个全局语句中,可以指定一个或多个以逗号分隔的名称。
在函数体内分配或引用时,所有列出的名称都将附加到封闭模块的作用域。
x = 5y = 55def fn() : global x x = [3, 7] y = [1, 33, 55] # a local 'y' is assigned and created here # whereas, 'x' refers to the global namefn()print(x, y)
在上面的代码中,“x”是一个全局变量,它将保留其在函数中所做的任何更改。另一个变量“y”具有局部范围,不会继续更改。
现在让我们看看全局声明的名称在两个不同的 Python 函数中的行为。
foo = 99def fn1() : foo = 'new' # new local foo createddef fn2() : global foo foo = 'update' # value of global foo changes
在下一个示例中,让我们看看全局如何使用 import 语句。
# mod_global.pydef fn1() : global x x = [1,2] ; y = [20, 200] # a local 'y' is created – availableonly within 'f1' # 'x' can be accessed anywhere after a call to 'f1'fn1()try : print(x, y) # name 'y' is not defined – errorexcept Exception as ex: print('y ->', ex) print('x ->', x)
# test1.pyimport mod_globalprint('test1 ->', mod_global.x)
# test2.pyfrom mod_global import *print('test2 ->', x)
实际上函数体内查找变量的原则 是就近原则。
#var = 5def fn1() : #var = [3, 5, 7, 9] def fn2() : #var = (21, 31, 41) print(var) fn2()fn1() # uncomment var assignments one-by-one and check the outputprint(var)
取消注释第一个“var”赋值后,输出为:
55
接下来,在取消注释第二个“var”赋值后,输出为:
[3, 5, 7, 9]5
最后,如果我们取消注释最后一个“var”赋值,则结果如下。
(21, 31, 41)5
Python 函数可以访问所def 语句中的名称。
X = 101 # global scope name - unuseddef fn1(): X = 102 # Enclosing def local def fn2(): print(X) # Reference made in nested def fn2() # Prints 102: enclosing def localfn1()
def fn1(): print('In fn1') X = 100 def fn2(): print('In fn2') print(X) # Remembers X in enclosing def scope return fn2 # Return fn2 but don't call itaction = fn1() # Make, return functionaction() # Call fn2() now: prints 100
输出如下。
In fn1In fn2100
在 Python 函数中, “return” 语句来返回一个值。
通常函数返回单个值。Python 允许使用集合类型(例如使用元组或列表)返回多个值。
通过返回元组并将结果赋回调用方中的原始参数名称。
def returnDemo(val1, val2) : val1 = 'Windows' val2 = 'OS X' return val1, val2 # return multiple values in a tuplevar1 = 4var2 = [2, 4, 6, 8]print('before return =>', var1, var2)var1, var2 = returnDemo(var1, var2)print('after return =>', var1, var2)
上面的代码给出了以下输出。
before return => 4 [2, 4, 6, 8]after return => Windows OS X
def getMin(*varArgs) : min = varArgs[0] for i in varArgs[1:] : if i < min : min = i return minmin = getMin(21, -11, 17, -23, 6, 5, -89, 4, 9)print(min)
输出如下。
-89
接下来是递归函数的示例。
def calcFact(num) : if(num != 1) : return num * calcFact(num-1) else : return 1print(calcFact(4))
输出如下。
24
Python一切都是对象,函数也不例外。
可以将函数对象分配给任何其他名称。
def testFunc(a, b) : print('testFunc called')fn = testFuncfn(22, 'bb')
输出为:
testFunc called
您甚至可以将函数对象传递给其他函数。
def fn1(a, b) : print('fn1 called')def fn2(fun, x, y) : fun(x, y)fn2(fn1, 22, 'bb')
输出为:
fn1 called
您还可以在数据结构中嵌入函数对象。
def fn1(a) : print('fn1', a)def fn2(a) : print('fn2', a)listOfFuncs = [(fn1, 'First function'), (fn2, 'Second function')]for (f, arg) in listOfFuncs : f(arg)
输出为:
fn1 First functionfn2 Second function
您可以从另一个函数返回函数对象。
def FuncLair(produce) : def fn1() : print('fn1 called') def fn2() : print('fn2 called') def fn3() : print('fn3 called') if produce == 1 : return fn1 elif produce == 2 : return fn2 else : return fn3f = FuncLair(2) ; f()
输出为:
fn2 called
Python 函数也有属性。
def testFunc(): print('I'm just a test function.')testFunc.attr1 = 'Hello'testFunc.attr2 = 5testFunc()print(dir(testFunc))
输出为:
I'm just a test function.['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'attr1', 'attr2']
您可以利用函数属性来存档状态信息,而不是使用任何全局名称或非本地名称。
与非局部变量不同,属性可以在函数本身所在的任何地方访问,甚至可以从其代码外部访问。
函数是对象,函数可以接收固定,可变参数,函数调用,嵌套函数等,变量作用域。这些知识都需要自己去实践体会。
联系客服