python学习笔记-函数,递归和内置函数
函数和过程
过程:就是没有返回值的函数
python中过程也是函数,就算没有返回值,也要返回个None
例子:
def test(x): y=x+1 return y print(test) #这是打印函数在内存中的地址 def test1(): pass def test2(): return 0 def test3(x): msg="hello" print(msg,x) return 1,2,3,'a',["steven","bob"],None t1=test1() t2=test2() t3=test3("jobs") print(t1) #None print(t2) #0 print(t3) #打印返回的值,是一个元组:(1, 2, 3, 'a', ['steven', 'bob'], None)
总结:
返回值数=0:返回None
返回值数=1:返回object
返回值数>1:返回tuple
参数与可变长参数
过量的参数
在运行时知道一个函数有什么参数,通常是不可能的。另一个情况是一个函数能操作很多对象。更有甚者,调用自身的函数变成一种api提供给可用的应用。
对于这些情况,python提供了两种特别的方法来定义函数的参数,允许函数接受过量的参数,不用显式声明参数。这些“额外”的参数下一步再解释。
注意args和kwargs只是python的约定。任何函数参数,你可以自己喜欢的方式命名,但是最好和python标准的惯用法一致,以便你的代码,其他的程序员也能轻松读懂。
位置参数
在参数名之前使用一个星号,就是让函数接受任意多的位置参数。
def multiply(*args): total = 1 for arg in args: total *= arg return total print(multiply(2, 3)) print(multiply(2, 3, 4, 5, 6))
python把参数收集到一个元组中,作为变量args。显式声明的参数之外如果没有位置参数,这个参数就作为一个空元组
关键字参数
python在参数名之前使用2个星号来支持任意多的关键字参数。
def accept(**kwargs): for keyword, value in kwargs.items(): print("%s => %r" % (keyword, value)) accept(foo='bar', spam='eggs')
注意:kwargs是一个正常的python字典类型,包含参数名和值。如果没有更多的关键字参数,kwargs就是一个空字典。
混合参数类型
任意的位置参数和关键字参数可以和其他标准的参数声明一起使用。混合使用时要加些小心,因为python中他们的次序是重要的。参数归为4类,不是所有的类别都需要。他们必须按下面的次序定义,不用的可以跳过。
1)必须的参数
2)可选的参数
3)过量的位置参数
4)过量的关键字参数
练习:
#例1 def add(x,y,z=5): res=x+y+z print(res) add(1,z=2,y=9) #位置参数必须在关键字参数的左边 #例2 def test(x,*args): #print(x) print(args) test(3,[4,5,6,7]) #结果为:([4, 5, 6, 7],) test(3,*[4,5,6,7]) #结果为:(4, 5, 6, 7),和test(3,4,5,6,7)一样 test(3) #结果为() #例3 def test(x,**kwargs): #print(x) print(kwargs) test(1,a=3,b=4,c=5) #{'a': 3, 'b': 4, 'c': 5} #test(1,a=3,b=4,c=5,c=5) #报错,一个参数不能传两个值 #例4 def test(x,*args,**kwargs): #print(x) print(args) print(kwargs) test(1,10,11,12,13,a=30,b=40,c=50) test(1,*[10,11,12,13],**{"a":30,"b":40,"c":50}) '''结果为: (10, 11, 12, 13) {'a': 30, 'b': 40, 'c': 50} (10, 11, 12, 13) {'a': 30, 'b': 40, 'c': 50} '''
局部变量与全局变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
name='steven' def change_name(): print('名字',name) change_name() #名字 steven def change_name(): name='帅哥一枚' print('名字',name) change_name() print(name) #steven def change_name(): global name #操作的是全局变量 name='帅哥一枚' print('名字',name) change_name() print(name) #帅哥一枚
补充:
NAME=["jobs","steven"] def test(): NAME.append("mark") print("我的朋友有:",NAME) test()
总结:如果函数的内部无global关键字,优先读取局部变量;
可读取全局变量,无法对全局变量重新赋值,但是对于可变类型,可以对全局变量的内部元素进行操作
如果函数中有global关键字,变量本质上就是全局的那个变量,可读取可赋值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#1、无global关键字 #---有声明局部变量 NAME=["jobs","steven"] def test(): NAME=["zhou"] NAME.append("mark") print("我的朋友有:",NAME) test() #['zhou', 'mark'] #--未声明局部变量 NAME=["jobs","steven"] def test(): NAME.append("mark") print("我的朋友有:",NAME) test() #['jobs', 'steven', 'mark'] #2、有global关键字 #---有声明局部变量 NAME=["jobs","steven"] def test(): global NAME NAME = ["zhou"] NAME.append("mark") print("我的朋友有:",NAME) test()#['zhou', 'mark'] #--错误的例子 # NAME=["jobs","steven"] # def test(): # NAME = ["zhou"] # global NAME # NAME.append("mark") # print("我的朋友有:",NAME) # test()#报错,局部变量在全局变量声明之前报错,不知道找哪个 #规范:全局变量变量名全部大写,局部变量变量名小写 #--未声明局部变量 NAME=["jobs","steven"] def test(): global NAME NAME.append("mark") print("我的朋友有:",NAME) test()#['jobs', 'steven', 'mark']
函数嵌套与作用域
#1、 def test1(): print("in the test1") def test(): print("in the test") return test1 res=test() print(res) #2、 name="jobs" def foo(): name="mark" def bar(): #name="steven" print(name) return bar a=foo() print(a) a() #bar() #定义是一部分,执行是一部分。虽然在最外面执行的bar().但是输出结果还是“mark”不论在那个位置调用函数。函数的作用域跟声明的时候有关。 #3、 def foo(): name="steven" def bar(): name="mark" def tt(): print(name) return tt return bar bar=foo() tt=bar() print(tt) tt() #mark foo()()() #mark
函数递归
在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身,就是递归
def calc(n): print(n) if int(n/2) == 0: return n res=calc(int(n/2)) return res r=calc(10) print(r)
例子:问路
import time person_list=["zhou","steven","jobs","mark","sandy"] def ask_way(person_list): print("-"*60) if len(person_list)==0: return "根本没人知道" person=person_list.pop(0) if person=="sandy": return "%s说:我知道,就在来福士,下地铁就是"%person print("Hi,美男[%s]:敢问路在何方" %person) print("%s回答说:我不知道,我帮你问问%s"%(person,person_list)) time.sleep(1) res=ask_way(person_list) print("%s问的结果是:%s"%(person,res)) return res res=ask_way(person_list) print(res)
结果为:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
------------------------------------------------------------ Hi,美男[zhou]:敢问路在何方 zhou回答说:我不知道,我帮你问问['steven', 'jobs', 'mark', 'sandy'] ------------------------------------------------------------ Hi,美男[steven]:敢问路在何方 steven回答说:我不知道,我帮你问问['jobs', 'mark', 'sandy'] ------------------------------------------------------------ Hi,美男[jobs]:敢问路在何方 jobs回答说:我不知道,我帮你问问['mark', 'sandy'] ------------------------------------------------------------ Hi,美男[mark]:敢问路在何方 mark回答说:我不知道,我帮你问问['sandy'] ------------------------------------------------------------ mark问的结果是:sandy说:我知道,就在来福士,下地铁就是 jobs问的结果是:sandy说:我知道,就在来福士,下地铁就是 steven问的结果是:sandy说:我知道,就在来福士,下地铁就是 zhou问的结果是:sandy说:我知道,就在来福士,下地铁就是 sandy说:我知道,就在来福士,下地铁就是
递归特性
1、必须有一个明确的结束条件
2、每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3、递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调动是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会增加一层,每当函数返回,栈就会减少一层。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
匿名函数
匿名函数就是不需要显式的指定函数
def calc(x): return x+1 print(calc(10)) #换成匿名函数 func=lambda x:x+1 print(func(10)) #print(lambda x:x+1) #输出函数地址 test=lambda x,y,z:(x+1,y+1,z+1) #返回多个值时当做元组处理。lambda用法时要手动加括号 print(test(1,2,3))#(2, 3, 4)
匿名函数主要是和其它函数搭配使用的
函数式编程
编程的三种方法论:
面向过程
函数式
面向对象
函数式编程可读性查,精简
特性:
1、不可变,不用变量保存状态,不修改变量
#非函数式 a=1 def incr_test1(): global a a+=1 return a print(incr_test1()) #函数式 n=1 def incr_test2(n): return n+1 print(incr_test2(2)) print(n)
2、第一类对象:函数即变量
函数名可以当做参数传递
返回值可以是函数名
高阶函数:
满足下面一种情形的就是高阶函数(1、函数接收的参数是一个函数名;2、返回值中包含函数)
# 把函数当做参数传给另一个函数 def foo(n): print(n) def bar(name): print("my name is %s" % name) #foo(bar) foo(bar("steven")) # 返回值中包含函数 def bar(): print("from bar") def foo(): print("from foo") return bar n = foo() n() #返回自己 def handle(): print("from handle") return handle n = handle() n()
尾递归调用优化:
在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)
# 非尾调用 def bar(n): return n def foo(x): return bar(x) + 1
#尾调用 def test1(): print("from test1") def test2(): print("from test2") return test1()
map函数
num_1=[1,2,10,4,3,7] def map_test(func,array): #func=lambda x=x+1 arrary=[1,2,10,4,3,7] ret=[] for i in array: res=func(i) # ret.append(res) return ret print(map_test(lambda x:x+1,num_1)) #使用map函数 res=map(lambda x:x+1,num_1) #获得的是个可迭代对象,在python2获得的就是个列表 print(res) #<map object at 0x0000021E578A0C18> print(list(res)) #[2, 3, 11, 5, 4, 8] msg="ajfaljfiejalf" print(list(map(lambda x:x.upper(),msg)))#['A', 'J', 'F', 'A', 'L', 'J', 'F', 'I', 'E', 'J', 'A', 'L', 'F']
filter函数
gentleman=["alex_ss","jobs_ss","steven","mark_ss"] print(filter(lambda n:not n.endswith("ss"),gentleman))#<filter object at 0x000002B2A39D0C18> res=filter(lambda n:not n.endswith("ss"),gentleman) print(list(res)) #['steven']
reduce函数
num_1=[1,2,3,100] def reduce_test(func,array,init=None): if init is None: res=array.pop(0) else: res=init for num in array: res=func(res,num) return res print(reduce_test(lambda x,y:x*y,num_1,10)) #6000 #reduce 用法 from functools import reduce print(reduce(lambda x,y:x*y,num_1,10)) #6000
总结:
map函数对一个列表进行特定处理,结果得出一个长度和顺序不变的列表,filter是对一个列表处理筛选一遍得出一个列表出来,reduce把一个完整的序列压缩处理成一个值
map处理序列中的每个元素,得到的结果是一个"列表",该列表元素个数与位置与原来一样
filter遍历序列找那个的每个元素,判断每个元素得到布尔值,如果是true则留下来
reduce处理一个序列,然后把序列进行合并操作
内置函数
print(abs(-2)) print(all([1,2,'1'])) print(all([1,2,'1',''])) #可迭代对象的每个值是true,返回true print(all('')) #true print(all([])) #可迭代对象是空,返回true print(all([0,'']))#false print(all([0,'',1]))#false print(bin(3)) #转化成二进制,结果:0b11 0b表示二进制 print(bool(None)) #空,None,0的布尔值为false,其余都为true name='你好' print(bytes(name,encoding='utf-8')) print(bytes(name,encoding='utf-8').decode('utf-8')) #decode():python3默认用uft-8解码 print(bytes(name,encoding='gbk')) print(bytes(name,encoding='gbk').decode('gbk')) #print(bytes(name,encoding='ascii')) #错误:ascii不能编码中文 print(chr(109)) #按照ascii码表对应的顺序输出值 print(dir(all)) #输出all下面的所有方法名 print(divmod(10,3)) #结果:(3, 1),得出商和余数 dict_str='{"name":"steven"}' print(eval(dict_str)) #把字符串中的数据结构提取出来 express="1+2*5-3" print(eval(express)) #把字符串中的表达式进行运算 #可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型 print(hash("9238121hkjk jkjijojo0")) help(all) print(hex(12)) #十进制--》16进制 print(oct(12)) #十进制--》8进制 print(isinstance(1,int)) #true print(isinstance([],list)) print(isinstance("abc",str)) print(globals())#打印全局变量 print(locals())#打印局部变量
max()
1、max函数处理的是可迭代对象,相当于一个for循环取出每个元素进行比较,注意,不同类型之间不能进行比较
2、每个元素件进行比较,是从每个元素的第一个位置依次比较,如果这一个位置分出大小,后面的都不需要比较了,直接得出这个元素。
例子:max与zip方法
#max场景1 l=[1,3,100,-3,9] print(max(l)) print(min(l)) print(list(zip(('a','b','c'),(1,2,3)))) #zip创建一个拉链的对象,左右对齐。结果:[('a', 1), ('b', 2), ('c', 3)] print(list(zip(('a','b','c'),(1,2,3,4))))#[('a', 1), ('b', 2), ('c', 3)] print(list(zip(('a','b','c','d'),(1,2,3))))#[('a', 1), ('b', 2), ('c', 3)] # p={'name':'steven','age':18,'gender':'none'} print(list(zip(p.keys(),p.values()))) #[('name', 'steven'), ('age', 18), ('gender', 'none')] print(list(p.keys()))#['name', 'age', 'gender'] print(list(p.values()))#['steven', 18, 'none'] print(list(zip('hello','12345'))) #zip里传的两个参数是序列类型(列表,字符串,元祖) #max场景2 age_dic={"age1":18,"age2":20,"age3":100} print(max(age_dic.values()))#比较的是value,但不知道是哪个key对应的 print(max(age_dic)) #默认比较字典的key #max场景3,结合zip print(list(max(zip(age_dic.values(),age_dic.keys())))) l=["a10","b12","c10"] print(list(max(l))) #['c', '1', '0'] #如果l=["a10","b12","c10",100].报错,整形和字符串不能比较,只能相同类型进行比较 #max场景4 people=[{"name":"alex","age":1000},{"name":"steven","age":800},{"name":"mark","age":100}] a=max(people,key=lambda dic:dic["age"]) print(a) #{'name': 'alex', 'age': 1000}
其他内置函数
#ord() print(ord("a")) #跟chr对应 #pow() print(pow(3,3)) #3**3 print(pow(3,3,2)) #3**3%2 #reversed() 反转 l=[1,2,3,4] print(l) print(list(reversed(l)))#[4, 3, 2, 1] #round() 四舍五入 print(round(3.6)) #set() 集合 print(set("hello"))#{'h', 'o', 'e', 'l'} #slice() #场景1,不使用时,可读性差 l="hello" print(l[3:5]) #场景2. l="hello" s1=slice(3,5) s2=slice(1,4,2) print(l[s1])#lo print(l[s2])#el print(s2.start) #输出切片的开始,1 print(s2.stop) #输出切片的结束,4 print(s2.step) #输出切片的步长,2 #sorted() l=[3,2,1,5,7] l1=[3,2,"a",1,5,7] print(sorted(l)) #[1, 2, 3, 5, 7] #print(sorted(l1)) #排序本质就是比较大小,不同类型之间不可以比较大小 people=[{"name":"alex","age":1000},{"name":"steven","age":800},{"name":"mark","age":100}] print(sorted(people,key=lambda dic:dic["age"])) #结果为:[{'name': 'mark', 'age': 100}, {'name': 'steven', 'age': 800}, {'name': 'alex', 'age': 1000}] name_dic={"mark":800,"steven":200,"jobs":500} print(sorted(name_dic)) #结果是按照key排序 ['jobs', 'mark', 'steven'] print(sorted(name_dic,key=lambda key:name_dic[key]))#['steven', 'jobs', 'mark'] print(sorted(zip(name_dic.values(),name_dic.keys())))#[(200, 'steven'), (500, 'jobs'), (800, 'mark')] #str()转化成字符串 print(str({"a":1})) dic_str=str({"a":1}) print(eval(dic_str)) #字符串中数据类型提取出来 #sum() l=[1,2,3,4] print(sum(l)) print(sum(range(5))) #type() msg='123' if type(msg) is str: msg=int(msg) res=msg+1 print(res) #vars() 跟一个列表对象,返回一个字典:不带参数,相当于locals(),打印局部变量的字典形式。有参数,相当于object.__dict__,查看对象下对所有方法的字典形式,没什么用 def test(): msg='djfaiefjaleji' print(locals())#{'msg': 'djfaiefjaleji'} print(vars())#{'msg': 'djfaiefjaleji'} test() print(vars(int)) #import 不能导入字符串 运行时import实际上调用操作系统,操作系统会找到__import__()方法去导入:import--->sys--->__import__() #__import__ 导入字符串的模块名 import os module_name='elementtreexml' m=__import__(module_name) xmlFilePath = os.path.abspath("movie.xml") root=m.readXml(xmlFilePath) m.traverseXml(root)