1、函数
1.1、编程的方式:
(1)面向对象 -->华山派 -->独门秘籍:类 -->定义关键字:class(2)面向过程 -->少林派 -->独门秘籍:过程 -->定义关键字:def(3)函数式编程 -->逍遥派 -->独门秘籍:函数 -->定义关键字:def
1.2、函数是什么?
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
2.3、函数语法定义:
函数语法:def 函数名(参数1,参数2,参数3,...): '''注释''' 函数体 return 返回的值python演示:def auth(user,password): ''' auth function :param user: 用户名 :param password: 密码 :return: 认证结果 ''' if user == 'kim' and password == '123': return 0 else: return 1user = input("用户名:").strip()pwd = input("密码:").strip()res=auth(user,pwd)print(res)执行结果:用户名:kim密码:1230
2.4、函数返回值
无return->None
return 1个值->返回1个值
return 逗号分隔多个值->元组
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
如果未在函数中指定return,那这个函数的返回值为None
什么时候该有返回值?
调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值
通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果
什么时候不需要有返回值?
调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值
通常无参函数不需要有返回值
2.5、函数的参数
形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应该与形参一一对应)实参:实际参数,调用函数时传给函数的参数,可以是变量,常量,表达式,函数,传给形参。区别:形参是虚拟的,不占用内存空间,形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据单向传送,实参传给形参,不能形参传给实参。★★★★★关键参数是不能写在位置参数前面的!!!!!!def test1(x,y): print(x,y)test1(1,2)-->位置调用,和形参一一对应test1(x=1,y=2)-->关键字调用,与形参顺序无关****************************************默认参数:def test1(x,y=2): -->y有默认值为2 print(x,y) test1(1,3)默认参数特点:调用参数的时候,默认参数非必须传递默认参数用途:默认安装值,端口等参数组:*args-->接收多个参数,以元组的方式进行存储**kwargs-->接受N个关键字参数,以字典的方式进行存储
2.6、总结:
#1、位置参数:按照从左到右的顺序定义的参数 位置形参:必选参数 位置实参:按照位置给形参传值def test1(x,y): print(x,y)test1(1,2) #位置参数test1(x=4,y=6) #关键字参数执行结果:1 24 6#2、关键字参数:按照key=value的形式定义的实参 无需按照位置为形参传值 注意的问题: 1. 关键字实参必须在位置实参右面 2. 对同一个形参不能重复传值#3、默认参数:形参在定义时就已经为其赋值 可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参) 注意的问题: 1. 只在定义时赋值一次 2. 默认参数的定义应该在位置形参右面 3. 默认参数通常应该定义成不可变类型def test2(x,y=3): #默认参数y的值为3 print(x,y)test2(2)test2(2,6)执行结果:2 32 6#4、可变长参数(*args,**kwargs): 可变长指的是实参值的个数不固定 而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它def test3(*args): #可变长参数,使用*args接收N个位置参数,并且以元组的方式存储 print(args)test3(1,2,3,4,5,6)执行结果:(1, 2, 3, 4, 5, 6)def test4(name,*args): #可变长参数和位置参数混合使用 print(name,args)test4('alex',4,5,6)test4(1,*[1,2,3])执行结果:alex (4, 5, 6)1 (1, 2, 3)def test5(x,y,**kwargs): #**kwargs接受N个关键字参数,以字典的方式进行存储 print(x,y) print(kwargs)test5(1,2,c=3,d=4,e=5)test5(1,y=2,**{'a':1,'b':2,'c':3})执行结果:1 2{'d': 4, 'e': 5, 'c': 3}1 2{'a': 1, 'b': 2, 'c': 3}def test6(*args,**kwargs): print(args) print(kwargs)test6(5,6,7,a=1,b=5) #位置参数必须在关键参数的前面,否则会报错执行结果:(5, 6, 7){'a': 1, 'b': 5}
3、全局与局部变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:
在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
school="oldboy" --->全局变量schooldef change_name(name): #global school -->强制修改全局变量,需要进行申明:global 变量名,最好别用此方法 school="MaGe linux" print("before change:",name,school) name="Alex li" #局部变量,只在函数体内生效,这个函数就是此变量的作用域 print("after change:",name)name="alex"change_name(name)print(name)print(school)执行结果:before change: alex MaGe linuxafter change: Alex lialexoldboy★★注意:在列表,字典,集合,类等特殊类型变量在函数体内是可以进行修改的,如下演示:names = ["Alex","Jack","Rain"]def change_name(): names[0] = "哈哈" print("inside :",names)change_name()print(names)执行结果:inside : ['哈哈', 'Jack', 'Rain']outside : ['哈哈', 'Jack', 'Rain']
4、函数递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:
(1).必须有一个明确的结束条件
(2)每次进入更深一层递归时,问题规模相比上次递归都应有所减少
(3)递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
def calc(n): print(n) if int(n / 2) == 0: return n return calc(int(n / 2))calc(10)执行结果:10521
5、函数式编程介绍
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。一、定义简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式: (1 + 2) * 3 - 4传统的过程式编程,可能这样写: var a = 1 + 2; var b = a * 3; var c = b - 4;函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样: var result = subtract(multiply(add(1,2), 3), 4);这段代码再演进以下,可以变成这样add(1,2).multiply(3).subtract(4)这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:merge([1,2],[3,4]).sort().search("2")因此,函数式编程的代码更容易理解。
###13.10、高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f): return f(x)+f(y)res = add(3,-6,abs) #abs本身为一个函数,取绝对值print(res)执行结果:9
6、函数练习:
1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数def count(msg): res={ 'num':0, 'string':0, 'space':0, 'other':0 } for s in msg: if s.isdigit(): res['num']+=1 elif s.isalpha(): res['string']+=1 elif s.isspace(): res['space']+=1 else: res['other']+=1 return resres=count('hello world ! 123')print(res)3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。def check_list(msg): while type(msg) == list: if len(msg) >2: msg=msg[0:2] return msgprint(check_list([1,2,3,4,5,6,7]))5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。def check_list2(seq): seq=seq[::2]---------->从头遍历到尾,步长为2 return seqprint(check_list2([1,2,3,4,5]))6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。方法一:def check_dict(seq): d={} for k, v in seq.items(): if len(v) > 2: d[k] = v[0:2] return dprint(check_dict({'k1':'abcdef','k2':[1,2,3,4],'k3':('a','b','c')}))执行结果:{'k2': [1, 2], 'k1': 'ab', 'k3': ('a', 'b')}方法二:def check_dict(seq): d={} for i in seq: if len(seq[i]) > 2: d[i] = seq[i][0:2] return dprint(check_dict({'k1':'abcdef','k2':[1,2,3,4],'k3':('a','b','c')}))执行结果:{'k2': [1, 2], 'k1': 'ab', 'k3': ('a', 'b')}