Python3.5基础——函数的定义与使用
Python3.5基础——函数的定义与使用
1、函数学习框架
2、函数的定义与格式
(1)定义
(2)函数调用
注:函数名称不能以数字开头,建议函数名称的开头用小写的字母
(3)函数有四种格式,分别是:无参数无返回值,有参数无返回值、无参数有返回值、有参数有返回值
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
# 无参数无返回值
defhello():
# 函数体/方法体
print("hello world")
hello()
# 有参数无返回值
defadd(x, y):
print(x + y)
add(10,20)
# 无参数有返回值
defsleep():
return"sleep"
s = sleep()
print(s)
# print(sleep()) 等价于上面两句
# 有参数有返回值
defsub(x, y):
returnx * y
res = sub(12,6)
print(res)
#运行结果
hello world
30
sleep
72
3、函数的参数
注:定义再函数体内的参数是形参,调用时传入的参数是实参。
函数参数包括:位置参数、关键字参数和不定个数参数
(1)位置参数、关键字参数
示例代码:
#位置参数
deftest(x,y,z):
print(x,y,z)
test(1,2,3)
#关键字参数
deftest1(x,y,z=10):
print(x,y,z)
test1(1,2,3)
test1(1,2)#关键字参数,z采用默认的参数值
test1(x=2,z=3,y=1)#调用时的关键字参数
#运行结果:
123
123
1210
213
(2)默认参数
注:带有默认值参数的形参必须放在参数的最后面的位置。
(3)不定个数参数,用*args 和 **kwarg
总结:
(1)定义时 *的作用 将位置实参装配成元组
定义时 **的作用 将关键字实参装配成字典
(2)调用时 *作用 将元组或列表打散成位置参数进行参数传递
调用时 **作用 将字典打散成关键字参数进行参数传递
#不定个数参数
deftest2(x,y,z,*args):
print(x,y,z,args)
#定义时 *的作用 将位置实参装配成元组
test2(1,2,3,4,6,7,8,9)
deftest3(x,y,z,**kwargs):
print(x,y,z,kwargs)
#定义时 **的作用 将关键字实参装配成字典
test3(1,2,3,a=6,b=19,c=8)
defts(x,*args,**kwargs):
print(x,args,kwargs)
ts(1,2,3,a=6,b=19,c=8)
deftest4(x,y,z):
print(x,y,z)
x = [1,2,3]
y = {"x":1,"y":"hello","z":"你好"}
test4(*x)#调用时 *作用 将元组或列表打散成位置参数进行参数传递
test4(**y)#调用时 **作用 将字典打散成关键字参数进行参数传递
#运行结果:
123(4,6,7,8,9)
123{'b':19,'a':6,'c':8}
1(2,3) {'b':19,'a':6,'c':8}
123
1hello 你好
4、函数的传值:基本类型传值调用、非基本类型参数传递调用(强引用与弱引用)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#基本类型传值调用
deftest(x):
print(x)
test(10)
#非基本类型参数传递调用
li = [1,2,3,4]
print(id(li))#打印传递前的地址
deftest1(x):
print(id(x))
x[0] =2#修改第一个参数为2
print(x)
test1(li)#强引用(传址调用,列表里面的内容会进行修改)
#test1(list(li)) #弱引用(用list可以消除强引用,不能修改列表里的元素)
foriinli:
print(i)
#运行结果:(强引用传址调用)
10
17741864
17741864
[2,2,3,4]
2
2
3
4
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#基本类型传值调用
deftest(x):
print(x)
test(10)
#非基本类型参数传递调用
li = [1,2,3,4]
print(id(li))#打印传递前的地址
deftest1(x):
print(id(x))
x[0] =2#修改第一个参数为2
print(x)
#test1(li) #强引用(传址调用,列表里面的内容会进行修改)
test1(list(li))#弱引用(用list可以消除强引用,传值调用,不能修改列表里的元素)
foriinli:
print(i)
#运行结果:(弱引用,传值调用)
10
18501544
18613272
[2,2,3,4]
1
2
3
4
#不可变对象——传递对象的值,修改值修改的是另一个复制对象,不影响原来对象本身
defgetNum(a):
a =10
print("函数内变量a的值:",a)
a =8
getNum(a)
print("函数外变量a的值:",a)
#可变对象——传递对象本身,函数内部修改值会影响对象本身
list01 = [0,1,2,3]
defgetNum1(num):
num.append(4)
print(num)
print(id(num))
getNum1(list01)
print(list01)
print(id(list01))
#运行结果:
函数内变量a的值:10
函数外变量a的值:8
[0,1,2,3,4]
5908280
[0,1,2,3,4]
5908280
5、函数的返回值
示例代码:
#多个返回值
defre(a,b):
a *=10
b *=10
returna,b
num = re(1,2)
print(type(num))#如果返回多个值,并且存在一个变量中,会以元组的形式保存
print(num)
#分别获取多个返回值
re1,re2 = re(3,4)
print(type(re1))
print(re1,re2)
#运行结果:
(10,20)
30 40
简单实例练习:
defoperation(a,b,opt):
ifopt =="+":
returna+b
elifopt =="-":
returna-b
elifopt =="*":
returna*b
elifopt =="/":
returna/b
else:
return"输入有误"
num1 = int(input("请输入第一个字符:"))
num2 = int(input("请输入第二个字符:"))
op = input("请输入运算符:")
result = operation(num1,num2,op)
print(result)
#运行结果:
请输入第一个字符:1
请输入第二个字符:2
请输入运算符:+
3
6、变量的作用域:全局变量与局部变量
在函数的内部,不能识别全局变量,想要在函数内部使用全局变量,需要关键字global,但不建议这样使用,使用global具有污染性。
(1)局部变量
(2)全局变量
(3)当全局变量与局部变量同名时,优先使用局部变量
#全局变量与局部变量同名
a =10#全局变量
print("全局变量a:%d"%a)
deftest01():
a =20
print("test01中的a:%d"%a)
deftest02():
print("test02中的a:%d"%a)
test01()
test02()
#运行结果:
全局变量a:10
test01中的a:20
test02中的a:10
(4)修改全局变量
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
i =20
deftest():
#i += 10 #函数内部直接修改全局的值(错误)
globali#函数内部修改全局的值用global关键字
i +=10
print(i)#获取全局变量的值
test()
#运行结果:
30
注:上边代码中,函数内修改不可变类型的全局变量,需要通过global关键字
总结:对不可变类型变量重新赋值,实际上是重新创建一个不可变类型对象,并将原来的变量指向新创建的对象。
如果没有其他变量引用原有对象的话(即:引用计数为0),原有对象就会被回收。
(5)可变类型的全局变量:函数内修改可变类型的全局变量,可以不使用global关键字
#函数内修改可变类型的全局变量——直接修改,无需使用global关键字
a = [100,200,300]
print("可变类型全局变量a:",a)
print("可变类型全局变量a的地址:%d"%id(a))
deftest01():
a.append(400)
print("test01函数内修改可变类型全局变量a:",a)
print("test01函数内修改可变类型全局变量后a的地址:%d"%id(a))
deftest02():
print("test02函数内使用可变类型全局变量a:",a)
print("test02函数内使用可变类型全局变量a的地址:%d"%id(a))
test01()
test02()
#运行结果:
可变类型全局变量a: [100,200,300]
可变类型全局变量a的地址:18241896
test01函数内修改可变类型全局变量a: [100,200,300,400]
test01函数内修改可变类型全局变量后a的地址:18241896
test02函数内使用可变类型全局变量a: [100,200,300,400]
test02函数内使用可变类型全局变量a的地址:18241896
7、匿名函数
示例代码:
#匿名函数——lambda
#语法:lambda arg1[,arg2...]:表达式 默认return
num =lambdaa,b:a+b
print(num(1,2))
#运行结果:
3
简单应用(一):
#四则运算——利用lambda表达式
defoperation(a,b,opt):
re = opt(a,b)
returnre
num1 = int(input("请输入第一个字符:"))
num2 = int(input("请输入第二个字符:"))
result = operation(num1,num2,lambdaa,b:a+b)
print(result)
#运行结果:
请输入第一个字符:2
请输入第二个字符:3
5
简单应用(二):
#列表中的字典元素进行排序——lambda表达式
students = [
{"name":"Joe","age":"18"},
{"name":"Tom","age":"20"},
{"name":"Susan","age":"16"}
]
students.sort(key=lambdax:x["name"])#对字典按照关键字name排序
print(students)
#运行结果:
[{'age':'18','name':'Joe'}, {'age':'16','name':'Susan'}, {'age':'20','name':'Tom'}]
8、递归函数
代码示例:
#函数的嵌套
deftest1():
print("in test1...")
deftest2():
test1()
print("in test2...")
deftest3():
test2()
print("in test3...")
test3()
#运行结果:
intest1...
intest2...
intest3...
#递归函数
deffunc(n):
print("进入第%d层梦"%n)
ifn ==3:
print("进入潜意识区")
else:
func(n+1)
print("从第%d层梦中醒来"%n)
func(1)
#运行结果:
进入第1层梦
进入第2层梦
进入第3层梦
进入潜意识区
从第3层梦中醒来
从第2层梦中醒来
从第1层梦中醒来
应用:求阶乘
#阶乘——利用while
i =1
num =1
whilei <=4:
num = num*i
i+=1
print(num)
#阶乘——利用递归
deffunc01(n):
ifn ==1:
return1
returnn*func01(n-1)
print(func01(4))
#运行结果:
24
24
利用递归实现阶乘的原理过程:
9、常用内置函数
示例代码:
#abs()——绝对值函数
num =-1
print(abs(num))
#sorted()——排序函数
list01 = [1,4,2,7,9,3]
print(sorted(list01))#由小到大排序
print(sorted(list01,reverse=True))#由大到小排序
#sum()——求和
print(sum(list01))
#round()——四舍五入,获取指定位数的小数
print(round(3.1415926,2))
#pow()——乘方数(幂)
print(pow(2,3))
#isinstance——类型判断
num1 =5
print(isinstance(num1,int))
#eval()——执行表达式或字符串作为运算
print(eval("1+3"))
#exec()——执行Python语句
exec('print("Hello")')
#运行结果:
1
[1,2,3,4,7,9]
[9,7,4,3,2,1]
26
3.14
8
True
4
Hello
10、高阶函数
示例代码:
#常用高阶函数
#map()
num1 = map(lambdax:x*2,[1,2,3,4,5])
print(num1)
foriinnum1:#遍历map对象的内容
print(i,end=" ")
print()
#filter()
num2 = filter(lambdax:x%2==1,[1,2,3,4,5,6,7,8,9,10])
print(num2)
forjinnum2:#遍历filter对象的内容
print(j,end=" ")
print()
#reduce()
from functool simport reduce
print(reduce(lambdax,y:x+y,[1,2,3,4],10))#10是起始值
#运行结果:
246810
13579
20
name = ["joe","jack","TOM","suSAN"]
age = [17,18,20,15]
sex = ["M","M","M","F"]
#案例一——格式化英文名。首字母大写,其他小写
names = map(lambda t:t[0:1].upper()+t[1:].lower(),name)
for stu_name in names:
print(stu_name,end=" ")
print()
#案例二——将三个序列结合到一起,形成一个集合
newStu = map(lambda n,a,s:(n,a,s),name,age,sex)
student = []
for tup in newStu:
student.append(tup)
print(student)
#案例三——过滤性别为男的用户
males = filter(lambda x:x[2] =="M",student)
man = []
for m in males:
man.append(m)
print(man)
#案例四——求性别为男的用户的平均年龄
from functools import reduce
man_count = len(man)
total_age = reduce(lambda x,y:x+y[1],man,0)
print("总年龄:",total_age)
print("平均年龄:%.2f"%(total_age/man_count))
#运行结果:
Joe Jack Tom Susan
[('joe',17,'M'), ('jack',18,'M'), ('TOM',20,'M'), ('suSAN',15,'F')]
[('joe',17,'M'), ('jack',18,'M'), ('TOM',20,'M')]
总年龄:55
平均年龄:18.33
11、约瑟夫环
(1)一群人围在一起坐成环状(如:N)
(2)从某个编号开始报数(如:K)
(3)数到某数(如:M)的时候,此人出列,下一个人重新报数
(4)一直循环,直到所有人出列,约瑟夫环结束
约瑟夫环实现代码:
#约瑟夫环问题
# n=9(总人数) m = 3(报数) k:索引
#k = (k+(m-1))%len(list)
deffunc(n,m):
#生成一个列表
people = list(range(1,n+1))
k =0#定义开始的索引
#开始循环报数
whilelen(people) >2:
k = (k+(m-1))%len(people)
print("kill:",people[k])
del(people[k])
print(k)
returnpeople
print(func(9,3))
#运行结果:
kill:3
2
kill:6
4
kill:9
6
kill:4
2
kill:8
4
kill:5
2
kill:2
1
[1,7]
12、函数重载
在Python中,没有函数重载,若非要使用函数重载,则后边的同名函数会覆盖掉前面的函数。
#函数重载
def test(x):
print(x)
def test(x,y):
print(x+y)
#test(1) #出错
test(1,2)#覆盖test(x)
#运行结果:
3
13、函数的嵌套和闭包
(1)函数嵌套:在函数内部再定义新的函数
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#函数嵌套
def test():
def test1():
def test2():
print("hello")
return test2
return test1
res = test()#test函数返回值res是一个函数,等价于res ==> test1
re = res()#res() ==>test1() ,test1函数返回值re是一个函数,re==>test2
re()#re() ==> test2()
#运行结果:
hello
(2)闭包:内部函数可以取到外部函数的局部变量
#闭包:内部函数可以取到外部函数的局部变量
deftest(x):
deftest1(y):
deftest2(z):
print(x+y+z)
returntest2
returntest1
res = test(10)
re = res(20)
re(30)
#运行结果:
6
14、装饰器
(1)形象举例:照片与相框
照片:被装饰的对象,相框:装饰对象。
装饰作用:动态扩展装饰,即:不会改变被装饰的对象(照片)的内容,只是动态改变装饰的对象(相框)。
(2)装饰器修饰无参数的函数
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#装饰器——日志管理
def log(func):#log(func)==> func = delete(delete函数作为实参传入到func)
def warp():
print("logger strating...")
func()#运行delete
print("logger ending...")
return warp
@log #用log来装饰delete,等价于delete = log(delete) = warp
defdelete():
print("deleting...")
delete()#执行warp
#运行结果:
logger strating...
deleting...
logger ending...
(3)装饰器修饰有参数和返回值的函数
#装饰器修饰有参数、有返回值的函数
deflog(func):#log(func)==> func = delete(delete函数作为实参传入到func)
defwarp(*args,**kwargs):
print("logger strating...")
res = func(*args,**kwargs)#运行delete
print(res)
print("logger ending...")
returnwarp
@log #用log来装饰delete,等价于delete = log(delete) = warp
defdelete(name,age):
print("deleting...")
print(name,age)
return"delete success"
delete("liu",20)#执行warp
#运行结果:
logger strating...
deleting...
liu20
delete success
logger ending...
(4)装饰器自身带有参数
#装饰器带有参数
deflog(i):
defwarp1(func):
defwarp2(*args,**kwargs):
print("logger strating...")
ifi>0:
print("logging success...")
func(*args, **kwargs)
else:
print("logging failed...")
print("logger ending...")
returnwarp2
returnwarp1
@log(1)
defdelete():
print("deleting...")
delete()
#运行结果:
logger strating...
logging success...
deleting...
logger ending...
#装饰器带有参数
deflog(i):
defwarp1(func):
defwarp2(*args,**kwargs):
print("logger strating...")
ifi>0:
print("logging success...")
func(*args, **kwargs)
else:
print("logging failed...")
print("logger ending...")
returnwarp2
returnwarp1
@log(-1)
defdelete():
print("deleting...")
delete()
#logger strating...
logging failed...
logger ending...
15、迭代器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#迭代器——笛卡尔积
impor titer tools
x = range(1,6)
coml = itertools.combinations(x,3)#排列
coml2 = itertools.permutations(x,4)#组合
y = ["a","b","c"]
coml3 = itertools.product(x,y)#笛卡尔积
coml4 = itertools.chain(coml,coml2,coml3)
forhincoml4:
print(h)
运行结果:
(1,2,3)
(1,2,4)
(1,3,4)
(2,3,4)
(1,2,3,4)
(1,2,4,3)
(1,3,2,4)
(1,3,4,2)
(1,4,2,3)
(1,4,3,2)
(2,1,3,4)
(2,1,4,3)
(2,3,1,4)
(2,3,4,1)
(2,4,1,3)
(2,4,3,1)
(3,1,2,4)
(3,1,4,2)
(3,2,1,4)
(3,2,4,1)
(3,4,1,2)
(3,4,2,1)
(4,1,2,3)
(4,1,3,2)
(4,2,1,3)
(4,2,3,1)
(4,3,1,2)
(4,3,2,1)
(1,'a')
(1,'b')
(1,'c')
(2,'a')
(2,'b')
(2,'c')
(3,'a')
(3,'b')
(3,'c')
(4,'a')
(4,'b')
(4,'c')