Python学习(六)函数
Chapter 3 函数
3.1 定义函数
*def
定义函数,包括函数名、参数和功能实现代码,若有返回值,则在逻辑代码中用return
返回。
- 结构
def function_name(parameters):
expressions
- 例1
def function():
print('This is a function')
a = 1+2
print(a)
定义了名为 function 的函数,函数没有接收参数,之后是函数的功能代码。
执行该脚本,并无任何输出,因为只定义了函数,而并没执行函数。
输入函数调用 function(), 函数内部的功能代码将会执行。
function()
输出结果:
This is a function
3
3.2 参数类型
-
形参:函数完成其工作所需的一项信息。
-
实参:调用函数时传递给函数的信息。
-
例2
定义函数
def greet_user(username):
print("Hello, " + username.title() + "!")
调用函数
greet_user('jesse')
输出
Hello, Jesse!
例子中,变量username是一个形参,值’jessi’是实参。
(1)必选参数
必选参数(required arguments)在函数定义必选参数后,每次调用都必须赋值,否则报错。
- 若调用没有指定参数,要求实参顺序和形参顺序相同
定义
def fun(a,b):
c = a+b
print("the c is',c)
传递参数
按顺序传递,参数个数和位置要按照定义
fun(1,2)
输出the c is 3
- 还可以指明特定的参数。每个实参由变量名和值组成。
fun(b=3,a=2)
输出the c is 5,实参顺序位置不受影响
(2)默认参数
默认参数(default arguments),定义函数时,可以给每个形参指定默认值。通过默认参数可以减轻函数调用的复杂度。
- 结构
def function_name(para_1,...,para_n=defau_n,..., para_m=defau_m):
expressions
- 例1
def sale_car(price,color='red',brand='carmy',is_second_hand=True):
print('price',price,
'color',color,
'brand',brand,
'is_second_hand",is_second_hand,)
定义了 sale_car 函数,参数为车的属性,但除了 price 之外,其他形参都是有默认值的。
调用函数 sale_car(1000), 与 sale_car(1000, ‘red’, ‘carmy’, True) 是一样的效果。
也可以在函数调用过程中传入特定的参数用来修改默认参数。如 sale_car(1000,color=‘blue’)。
- 默认值还能将参数变为可选
- 例2
定义
def get_formatted_name(first_name, middle_name, last_name):
full_name = first_name + ' ' + middle_name + ' ' + last_name
return full_name.title()
调用
musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)
输出
John Lee Hooker
但不是每个人都有中间名,因此将函数修改成:
def get_formatted_name(first_name, last_name, middle_name=''):
full_name = first_name + ' ' + middle_name + ' ' + last_name
return full_name.title()
调用
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
输出
Jimi Hendrix
- 使用默认值时,在形参列表中必须先列出没有默认值的形参, 再列出有默认值的实参
- 当有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
- 默认参数必须指向不变对象
(3)可变参数
可变参数(arguments),不确定参数的个数,即传入参数可变,可避免将参数封装在list
或tuple
。
- 结构
def function_name(*args):
expressions
- 例
定义
def report(name,*grades):
total_grade = 0
for grade in grades:
total_grade += grade
print(name,'total grade is',total_grade)
定义的函数传入必须参数name,和可变参数*grade,是可以迭代的对象,可以是数值、列表或元组等。
调用
report('Mike',8,9)
调用时输入姓名和各科成绩
输出
Mike total grade is 17
输出姓名和总成绩。
- 可变参数在函数定义时,不能出现在特定参数和默认参数前面,否则会吞噬。
(4)关键字参数
关键字参数(keyword arguments)可以含任意个数参数名的参数,这些参数名在定义时没有出现,在函数内部自动封装成一个字典dict
。
- 结构
def function_name(**kwargs):
expressions
- 例1
定义
def person(name,**kw):
print('name:',name,'age:',age,'other:',kw)
调用
person('Mike',30,gender='M',city='Beijing')
输出
name: Mike age: 30 other: {'city': 'Beijing'}
- 例2
定义
def portrait(name,**kw):
print('name',name)
for k,v in kw.items(): #dict.items() 可遍历字典(键,值)
print(k,v)
调用
portrait('Mike', age=24, country='China', education='bachelor')
输出
name Mike
age 24
country China
education bachelor
(5)命名关键字参数
关键字参数可以不受限制地通过函数调用来传入。若要显示关键字函数的名字,可使用命名关键字参数。
- 结构
def function_name(arg1,arg2,*,arg3,arg4):
expressions
需要*作为特殊分隔符,后面的参数为命名关键字参数。
- 例
定义
def person(name, age, *, city, job):
print(name, age, city, job)
调用
person('Jack', 24, city='Beijing', job='Engineer')
输出
Jack 24 Beijing Engineer
- 与位置参数不同,命名关键字参数必须传入参数名,否则报错
(6)参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数可以组合使用。
定义顺序:必选→默认→可变→命名关键字→关键字参数
- 例
定义
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
调用
f1(1, 2, 3, 'Hello', 'Bye', x=99)
输出
a = 1 b = 2 c = 3 args = ('Hello', 'Bye') kw = {'x': 99}
- 可以用
func(*args, **kw)
的形式调用任意函数,无论参数如何定义。可以理解成提供位置参数来拆解元组,提供关键字参数来拆解字典。
调用
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)
输出
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
3.3 返回值
函数返回的值称为返回值。用return
实现。
函数可以返回任何类型的值,包括列表、字典等。
(1)返回简单值
如1.5.2 (2)的例2,利用return返回人的英文全名。
def get_formatted_name(first_name, last_name, middle_name=''):
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
(2)返回字典
- 例
定义
def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person
该函数返回一个字典, 其中包含有关一个人的信息
调用
musician = build_person('jimi', 'hendrix')
print(musician)
输出
{'first': 'jimi', 'last': 'hendrix'}
3.4 递归函数
函数内部可以调用其他函数。如果一个函数在内部调用函数本身,这个函数就是递归函数。
- 例1
定义
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
这里的函数fact(n)
,相当于计算阶乘
fact(n)=n!=1×2×3×⋅⋅⋅×(n−1)×n=(n−1)!×n=fact(n−1)×n
因此,fact(n)可以表示为n x fact(n-1),只有n=1需要特殊处理
调用
fact(5)
输出
120
递归函数可以写成循环的方式,但是循环的逻辑不够清晰。递归函数定义简单,逻辑清晰。
栈(stack),又名堆栈,是限定仅在表尾(栈顶)进行插入和删除操作的线性表(表头成为栈底)。
使用递归函数要防止栈溢出。每次调用,栈就会加一层栈帧,每当函数返回就会减少一层栈帧。但是栈的大小是有限的,递归调用的次数过多会导致栈溢出。如调用fact(1000)
,就会报错。
-
解决递归调用栈溢出的方法是通过尾递归优化。指的是在函数返回的时候,调用自身本身,并且,
return
语句不能包含表达式。这样,interpreter会优化尾递归,无论递归调用多少次,都只占用一个栈帧,避免栈溢出。 -
例2
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
可以看到,return fact_iter(num - 1, num * product)
返回递归函数本身,num - 1和num * product在函数调用前就会被计算,不影响函数调用。
fact(5)对应的fact_iter(5, 1)的调用如下:
===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120
3.5 局部和全局变量
(1)局部变量
局部变量的作用域在某个函数的内部范围。
- 例
先定义一个函数
def fun():
a = 10
print(a)
return a+100
print(fun())
此时输出
10
110
这里定义了一个局部变量a
,作用域在函数fun
内部,在函数外则不是局部变量的a
。
(2)全局变量
全局变量的作用域在所编写的整个程序。全局变量一般全部用大写字母表示,便于辨认。
- 例
定义
APPLE = 100
def fun():
a = 10
print(a)
return a+100
print(APPLE)
print(a)
此时只能输出100,而输出a则报错,因为a是局部变量。
函数中调用全局变量
APPLE = 100
def fun():
a = APPLE
return a+100
print(APPLE)
print(fun())
输出
100
200
- 函数内定义全局变量
APPLE = 100
def fun():
global a
a = 20
return a+100
print(APPLE)
print(a)
- 在外部调用能在局部中修改的全局变量。即在函数中使用函数外的变量,可使用
global
关键字。
打印APPLE输出100,输出a会报错。但是python3.7.0版本以上,支持函数体内声明全局变量。因此一般在外部先赋值None。
APPLE = 100
a = None
def fun():
global a
a = 20
return a+100
print(APPLE)
print('a past=',a)
print(fun())
print('a now=',a)
100
a past= None
120
a now =20
====================================================================
Python学习的内容参考
《Python编程:从入门到实践》-[美] Eric Matthes
《21天学通PYTHON》
莫烦Python
廖雪峰的Python教程
等