零基础入门学Python系列内容的学习目录 → \rightarrow →零基础入门学Python系列内容汇总。
函数(上)
需要学习的基础知识有:函数、参数、闭包、lambda表达式、递归等。因本部分内容较多,故分为上下两个篇章。
1、2、3部分内容见零基础入门学Python(六)—— 函数(上)
4、5、6、7部分内容见零基础入门学Python(六)—— 函数(下)
1. Python的乐高积木
为了使得程序的代码更为简单,就需要把程序分解成较小的组成部分,有三种方法可以实现:函数、对象和模块。
1.1 创建和调用函数
我们之前使用的BIF就是Python帮我们封装好的函数,用的时候很方便,根本不需要去想实现的原理。一个程序可以按照不同功能的实现分割成许许多多的代码块,每一个代码块就可以封装成一个函数。
在Python中创建一个函数用def
关键字:
example1: >>>def myFirstFunction():
print(“这是我创建的第一个函数!”)
要注意的是,在函数名后要加上一对小括号。这对括号是必不可少的,因为有时候需要在里面放点东西。
在Python中调用一个函数,就是直接写出函数名加上小括号即可:
example2: >>>myFirstFunction()
这是我创建的第一个函数!
函数的调用机制和运行机制:当函数myFirstFunction()
发生调用操作的时候,Python会自动往上找到def myFirstFunction()
的定义过程,然后依次执行该函数所包含的代码块部分。只需要一条语句,就可以轻松实现函数内的所有功能。
假如要把刚才的内容打印三次,只需要调用三次函数即可:
example3: >>>for i in range(3):
myFirstFunction()
这是我创建的第一个函数!
这是我创建的第一个函数!
这是我创建的第一个函数!
1.2 函数的参数
之前在函数名后加的一对小括号里面放的东西就是函数的参数,参数会使得函数可以实现个性化。
example1: >>>def mySecondFunction(name):
print(name + “,你好!”)
>>>mySecondFunction(“小明”)
小明,你好!
>>>mySecondFunction(“张三”)
张三,你好!
如果需要使用多个参数的话,只需要用逗号隔开即可:
example2: >>>def add(num1, num2):
print(num1 + num2)
>>>add(1, 2)
3
1.3 函数的返回值
有时候需要函数为我们返回一些数据来报告执行的结果,所以函数需要返回值。在函数中使用关键字return
,后面跟着的就是指定要返回的值:
example1: >>>def add(num1, num2):
return num1 + num2
>>>add(1, 2)
3
2. 灵活即强大
2.1 形参和实参
参数从调用的角度来说,分为形式参数(parameter)和实际参数(argument)。形参是指函数创建和定义过程中小括号里的参数,而实参则是指函数在被调用的过程中传递进来的参数。
example1: >>>def myFirstFunction(name):
print(name)
>>>myFirstFunction(“小明”)
小明
其中,myFirstFunction(name)
的name
是形参,因为它只代表一个位置、一个变量名;而调用myFirstFunction("小明")
传递的"小明"是实参,因为它是一个具体的内容,是赋值到变量名中的值。
2.2 函数文档
函数文档的作用是描述该函数的功能。
example1: >>>def exchangeRate(dollar):
" " "美元 -> 人民币
汇率暂定为6.5
" " "
return dollar * 6.5
>>>exchangeRate(10)
65.0
在函数开头写下的字符串是不会打印出来的,但它会作为函数的一部分存储起来。这个称为函数文档字符串,它的功能跟注释是一样的。不一样的是函数的文档字符串可以通过特殊属性_ _doc_ _
获取:
example2: >>>exchangeRate._ _ doc _ _
’ 美元 -> 人民币 \n\t 汇率暂定为6.5 \n\t ’
另外,当我们想用一个函数但却不确定其用法的时候,可以通过help()
函数来查看函数的文档。
example3: >>>help(exchangeRate)
Help on function exchangeRate in module _ _ main _ _ :
exchangeRate(dollar)
美元 -> 人民币
汇率暂定为6.5
2.3 关键字参数
普通的参数叫位置参数,通常在调用一个函数的时候,我们可能会把位置参数的顺序弄乱以至于函数无法按照预期实现,因此就有了关键字参数,可以简单地解决这个潜在的问题。
example1: >>>def saySomething(name, words):
print(name + ’ -> ’ + words)
>>>saySomething(“小明”, “你好!”)
小明 -> 你好!
>>>saySomething(“你好!”, “小明”)
你好! -> 小明
>>>saySomething(words = “你好!”, name = “小明”)
小明 -> 你好!
关键字参数其实就是在传入实参时指定形参的变量名。
2.4 默认参数
默认参数是在定义的时候赋予了默认值的参数:
example1: >>>def saySomething(name = “小明”, words = “你好!”):
print(name + ’ -> ’ + words)
>>>saySomething( )
小明 -> 你好!
>>>saySomething(“张三”, “再见!”)
张三 -> 再见!
>>>saySomething(words = “好久不见!”, name = “李四”)
李四 -> 好久不见!
使用默认参数的话,就可以不带参数去调用函数。默认参数和关键字参数的区别为:
- 关键字参数是在函数调用的时候通过参数名指定要赋值的参数,这样做就不怕因为搞不清参数的顺序而导致参数调用出错。
- 默认参数是在参数定义过程中为形参赋值,当函数调用的时候不传递实参,则默认使用形参的初始值代替。
2.5 收集参数
收集参数大多时候也被称为可变参数,编写程序时,有时候程序员也不知道这个函数到底需要多少个参数,这时候仅需要在参数前面加上星号( *
)即可:
example1: >>>def test( * params):
print(“有 %d 个参数” % len(params))
>>>test( ‘H’, ‘e’, ‘l’, ‘l’, ‘o’)
有 5 个参数
>>>test( ‘小明’, ‘e’, 123)
有 3 个参数
如果在收集参数后边还需要指定其他参数,在调用函数的时候就应该使用关键字参数来指定,否则Pyhton就会把实参列入收集参数的范畴。
example2: >>>def test( * params, extra):
print(“收集参数是:”, params)
print(“位置参数是:”, extra)
>>>test(1, 2, 3, 4, 5)
Traceback (most recent call last):
File “
Pyhton就是把标志为收集参数的参数们打包成一个元组。如果编程时参数中带有收集参数,那么建议将其他参数设置为默认参数,这样不容易出错。
example3: >>>def test( * params, extra = “8”):
print(“收集参数是:”, params)
print(“位置参数是:”, extra)
>>>test(1, 2, 3, 4, 5)
收集参数是: (1, 2, 3, 4)
位置参数是: 5
星号( *
)其实既可以打包又可以“解包”。假如我们需要将一个列表a
传入test
函数的收集参数 * params
中,那么调用test(a)
时便会出错,此时需要在a
前边加上个星号( *
)表示实参需要“解包”后才能使用:
example4: >>>def test( * params):
print(“有 %d 个参数” % len(params))
print(“第二个参数是” , params[1])
>>>a = [1, 2, 3, 4, 5]
>>>test(a)
有 1 个参数
Traceback (most recent call last):
File “
Python还有另一种收集方式,就是用两个星号( **
)表示,两个星号的收集参数表示将参数们打包成字典的形式。
3. 我的地盘听我的
3.1 函数和过程
函数(function)是有返回值的,而过程(procedure)是简单、特殊并且没有返回值的。Pyhton严格来说只有函数,没有过程!
example1: >>>def hello( ):
print(“Hello~”)
>>>print(hello( ))
Hello~
None
通过上面例子可以发现,调用print(hello( ))
之后打印了两行文字。当不写return
语句的时候,Pyhton会默认函数是return None的,所以说Pyhton所有的函数都有返回值。
3.2 再谈谈返回值
在许多编程语言中,我们说一个函数是整型,其实就是指这个函数会返回一个整型的返回值。而Pyhton不同,Pyhton可以动态确定函数的类型,而且函数还能返回不同类型的值。另外,Pyhton似乎还可以同时返回多个值:
example1: >>>def test( ):
return[1, ‘小明’, ‘abc’]
>>>test( )
[1, ‘小明’, ‘abc’]
Pyhton可以利用列表打包多种类型的值一次性返回,也可以直接用元组的形式返回多个值:
example2: >>>def test( ):
return 1, ‘小明’, ‘abc’
>>>test( )
(1, ‘小明’, ‘abc’)
3.3 函数变量的作用域
变量的作用域就是平时所说的变量可见性,一般的编程语言都有局部变量(Local Variable)和全局变量(Global Variable)之分。看一个例子:
def discounts(price, rate): final_price = price * rate return final_price old_price = float(input('请输入原价:'))rate = float(input('请输入折扣率:'))new_price = discounts(old_price, rate)print('打折后价格是:', new_price)
请输入原价:10
请输入折扣率:0.7
打折后价格是: 7.0
在函数discounts()
中,两个参数是price
和rate
,还有一个是final_price
,它们都是discounts()
函数中的局部变量。如果将代码修改如下:
def discounts(price, rate): final_price = price * rate return final_price old_price = float(input('请输入原价:'))rate = float(input('请输入折扣率:'))new_price = discounts(old_price, rate)print('打折后价格是:', new_price)print('这里试图打印局部变量final_price的值:', final_price)
请输入原价:10
请输入折扣率:0.7
打折后价格是: 7.0
Traceback (most recent call last):
File “C:\Users\Administrator\Desktop\1.py”, line 9, in < module >
print(‘这里试图打印局部变量final_price的值:’, final_price)
NameError: name ‘final_price’ is not defined
运行之后就会报错,错误原因为final_price
没有被定义过,Python找不到final_price
这个变量。这是因为final_price
只是一个局部变量,它的作用范围之在它的地盘上——discounts()
函数的定义范围内有效。
总结一下:在函数里边定义的参数以及变量,都称为局部变量,出了这个函数,这些变量都是无效的。Python在运行函数的时候,利用栈(Stack)进行存储,当执行完该函数后,函数中的所有数据都会被自动删除,所以在函数外边是无法访问到函数内部的局部变量的。
与局部变量相对的是全局变量,上述程序中old_price
、new_price
、rate
都是在函数外边定义的,它们都是全局变量,全局变量拥有更大的作用城。例如在函数中可以访问到它们:
def discounts(price, rate): final_price = price * rate print('这里试图打印全局变量old_price的值:', old_price) return final_price old_price = float(input('请输入原价:'))rate = float(input('请输入折扣率:'))new_price = discounts(old_price, rate)print('打折后价格是:', new_price)
请输入原价:10
请输入折扣率:0.7
这里试图打印全局变量old_price的值:10.0
打折后价格是: 7.0
在Pyhton中,我们可以肆无忌惮的访问一个全局变量,但当试图修改它时就需要小心了。看如下所示代码:
def discounts(price, rate): final_price = price * rate old_price = 20 print('在全局变量中修改后old_price的值:', old_price) return final_price old_price = float(input('请输入原价:'))rate = float(input('请输入折扣率:'))new_price = discounts(old_price, rate)print('全局变量old_price现在的值是:', old_price)print('打折后价格是:', new_price)
请输入原价:10
请输入折扣率:0.7
在全局变量中修改后old_price的值: 20
全局变量old_price现在的值是: 10.0
打折后价格是: 7.0
如果在函数内部试图修改全局变量,那么Python会创建一个新的局部变量替代(名字跟全局变量相同),但真正的全局变量是纹丝不动的。
关于全局变量,我们也来总结一下:全局变量在整个代码段中都是可以访问到的,但是不要试图在函数内部去修改全局变量的值,因为那样Python会自动在函数内部新建一样的局部变量代替。如果想在函数里边去修改全局变量的值,可以在函数里边嵌套定义一个新的函数。
后半部分内容见零基础入门学Python(六)—— 函数(下)。