一.函数是什么:
python中函数定义:函数是逻辑结构化和过程化的一种编程方法。定义函数的方法为:
def function(): ""The function definitions"" do something return reselut def:定义函数的关键字 function 函数名 ()括号内可定义形参或者实参 ""可描述函数功能,非必选 结构体:do somethin,完成某种功能 return:将函数结果返回
二.使用函数的好处:
1.减少代码重用
2.保持一致性,易维护。相同功能可以使用同一个函数,功能发生改变时,直接修改函数即可
3.扩展性更好
三.函数的参数(实参,形参,可选参数,默认参数)
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
def test(a): #a为形参,在函数结构体中起到占位的作用 return a*a test(1) #1为实参
3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
def test(a,b,c,d) print(a) print(b) print(c) print(d) test(1,d=2,c=3,b=1) ''' 使用关键字传参,可不用注意参数的位置 '''
4.可选参数 *args **kwargs(如果同时存在,**kwargs位置需要在*args后面)
*args以元组的形式传递多个参数
def fun(*args): print(args) print(type(args)) fun(1,2,3,4) 结果: (1, 2, 3, 4) <class 'tuple'>
**kwargs 以字典的形式传递多个参数,所以参数需要是
def fun(**kwargs): print(kwargs) print(type(kwargs)) fun(a=1,b=2,c=3,d=4) 输出结果: {'a': 1, 'b': 2, 'c': 3, 'd': 4} <class 'dict'>
5.默认参数
设置好默认参数,如果该形参参数无对应的实参,则使用默认参数
def fun(a='b'): print(a) fun() fun('a') 输出结果 b a
四.局部变量和全局变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
name=123 def fun(): print(name) fun() 输出结果: 123
2.没有global关键字,则在函数中重新定义了变量,则函数内使用局部变量,全局变量保存不变
name=123 def fun(): name=234 print(name) fun() print(name) 输出结果: 234 123
由此可知,函数没有global关键字时,对全局变量只有读的权限,没有重新赋值的权限。需要注意的是:当全局变量为可变数据类型(列表,字典)时,函数是可以进行列表内容的修改。由此可见得,函数无法为全局变量开辟新的内存空间,但是可以对其内存地址存储内容进行修改。
name=[1,2,3,4] def fun(): name.append(5) print(name) fun() print(name) 输出结果: [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
3.有global关键字,且重新定义了全局变量。则会修改全局变量。
name=123 def fun(): global name name=234 print(name) fun() print(name) 输出结果: 234 234
我们要注意,不能在函数内,global前再定义变量,这样global无法区分你要申请的是全局变量还是 局部变量,会导致报错。
name=234 def fun(): name = 123 global name print(name) fun() 报错信息: SyntaxError: name 'name' is assigned to before global declaration
4.有global关键字,则定义的变量在全局变量中不存在,则创建全局变量。
def fun(): global name name=234 print(name) def fun1(): print('fun1',name) fun() fun1() 输出结果: 234 fun1 234
当我们无论在内嵌多少层的函数中使用global时,他都会变为全局变量。在内存中,可理解为:
global在此告一段落,接下来,介绍一下内嵌函数如何使用上层函数的变量。
nonlocal 关键字,定义了内嵌函数使用上层函数的变量
name=234 def fun(): name=1 def fun1(): nonlocal name print('fun1',name) fun1() fun() 输出结果: fun1 1
如果我们在第一层函数上使用该关键字,则会报错。所以不能在第一层函数使用该关键字。
def func(): #定义函数时,将函数内容以字符串形式保存在内存里 print('test') return func print('haha') #第一步,执行打印命令 func() #调用函数,将内存中存储的字符串当命令使用 a=func() #将func的内存地址赋值给变量名a a() #通过a来调用函数func 打印结果: haha test test test
函数调用前,都需要先将函数内容读取到内存中,再进行调用。和变量一样。我们定义变量时,会先将变量名和内容读取到内容中。当我们在调用变量名时,如果内存中午对应的值,则会报错。
错误示例: print(name) name='haha' func() def func(): print('this is func')
当我们执行函数时,只要函数内容已经存在内存中,则不分它存储的前后顺序。如下示例,虽然在定义函数时,func()调用func1时,func1并未定义,但是执行时func,func1都已经定义好了,故执行未报错。
def func(): print('this is func') func1() def func1(): print('this is func1') func() 输出结果: this is func this is func1
六.递归函数
递归函数:在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身,则是递归函数。
1 def calc(n): 2 print(n) 3 if int(n/2) ==0: 4 return n 5 return calc(int(n/2)) 6 7 calc(10) 8 9 输出: 10 10 11 5 12 2 13 1
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
由于递归函数的效率性不高,所以可以使用尾部调用来进行调优。即在函数的最后一步进行函数调用(最后一步不一定在最后一行)。这样就可以再调用函数完,即可释放内存。
函数的作用域
函数变量的作用域取决去它所在的内存位置,而不是在代码中所调用的位置。例如:
def scope(): scope_var='this is scope' def scope1(): scope_var='this is scope1' scope1() print(scope_var) return scope1 var=scope() #scope1 ''' 虽然是在主程序中直接调用了scope1函数,但是scope_var='this is scope1'的作用域还是只在scope函数下的scope1函数中,
这是因为python在读取函数定义时,已经按照相应层级读取到内存中。在主程序的调用只是直接调用内存而已 '''
高阶函数
满足俩个特性任意一个即为高阶函数
1.函数的传入参数是一个函数名
2.函数的返回值是一个函数名
map函数
map(func, *iterables) --> map object,处理序列中的每个元素,得到的结果是一个‘列表 ’,该‘列表’元素个数及位置与原来一样。map函数的原理如下:
def map_test(func,list_name): res=[] for i in list_name: res.append(func(i)) return res def add_one(n): return n*n test=[1,2,3,4,5] print(map_test(add_one,test))
可以用lambda来处理对象
print(list(map(lambda x:x+1,[1,2,3,4])))
filter函数
filter(function or None, iterable) --> filter object,遍历序列中的每个元素,判断每个元素的布尔值,如果为Ture,则留下该值。filter的原理如下 :
name=['sb1','sb2','3sb','xb'] def func(item): return not item.startswith('sb') def filter_test(func,item): new_list=[] for i in item: if func(i): new_list.append(i) return new_list print(filter_test(func,nam
可以用lambda来处理对象
list(filter(lambda x:not x.startswith('sb'),name))
reduce函数
reduce(function, sequence[, initial]) -> value,reduce()处理一个序列,然后把序列进行合并操作。原理如下:
def func(res,i): return res+i def reduce_test(func,seq,init=None): if init == None: res=seq.pop(0) else: res=init for i in seq: res=func(res,i) return res seq=[1,2,3,4,5,6,] print(reduce_test(func,seq))
用lambda来处理对象
from functools import reduce seq=[1,2,3,4,5,6,] print(reduce(lambda x,y:x+y,seq))
内置函数
#abs() print(abs(-1)) #去绝对值 #all() print(all([1,'',None])) #判断序列元素布尔值是否都为True,有一个为False,则返回False.空列表,空字符串等返回Ture print(all('')) #True print(all([''])) #False #any print(any([1,'',None])) #判断序列元素布尔值是否都为False,有一个为True,则返回True.空列表,空字符串等返回False print(any('')) #False print(any([1,'',None])) #True #bin bin(12) #将十进制转换为二进制 #bool() 判断bool值 print(bool(0)) #chr 根据序号找到acsii码表对应的字符 print(chr(97)) #ord 根据字符,找出对应的ascii码对应的序号 print(ord('a')) #compile() 将source编译为代码或者AST对象。代码对象能够通过exec语句来执行或者eval()进行求值。 没什么用。忽略 #divmod(x, y) 返回元组(x//y, x%y),即返回商的整数和余数部分 print(divmod(3,2))
字典的运算:最小值,最大值,排序 salaries={ 'egon':3000, 'alex':100000000, 'wupeiqi':10000, 'yuanhao':2000 } 迭代字典,取得是key,因而比较的是key的最大和最小值 >>> max(salaries) 'yuanhao' >>> min(salaries) 'alex' 可以取values,来比较 >>> max(salaries.values()) 100000000 >>> min(salaries.values()) 2000 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键 >>> max(salaries,key=lambda k:salary[k]) 'alex' >>> min(salaries,key=lambda k:salary[k]) 'yuanhao' 也可以通过zip的方式实现 salaries_and_names=zip(salaries.values(),salaries.keys()) 先比较值,值相同则比较键 >>> max(salaries_and_names) (100000000, 'alex') salaries_and_names是迭代器,因而只能访问一次 >>> min(salaries_and_names) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: min() arg is an empty sequence sorted(iterable,key=None,reverse=False)