函数
一、函数解释:
编程中的函数不同于数学中的函数。定义:函数是将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。
函数的特性:
1、代码重用 2、保持一致性 3、可扩展性
二、函数的创建:
2.1 格式:
1 def 函数名(参数列表): 2 函数体 3 # 4 def hello(): 5 print('hello') #函数调用
2.2 函数命名规则:
1、函数名必须以下划线或字母开头,可以包含任意字母,数字或下划线的组合。不能使用任何的标点符号。
2、函数名区分大小写。
3、函数名不能是保留字。
2.3 形参和实参:
形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参
区别:形参是虚拟的,不占用内存空间。形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据传送单向,实参传给形参,不能形参传给实参。
克服代码重用,可扩展并保持一致,为文件加上时间 1 import tim 2
3 def logger(n): 4 time_format='%Y-%m-%d %X' 5 time_current=time.strftime(time_format) 6 with open('日志记录','a') as f: 7 f.write('%s end action%s ' %(time_current,n)) 8 9 def action1(n): 10 print('starting action1...') 11 logger(1) 12 13 def action2(n): 14 print('starting action2...') 15 logger(2) 16 17 def action3(n): 18 print('starting action3...') 19 logger(3) 20 action1(11) 21 action2(22) 22 action3(33)
-----------------------------------------------
# starting action1...
starting action2...
starting action3...
三、函数的参数:
1、必备参数
2、关键字参数
3、默认参数
4、不定长参数
1、必需参数:须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
1 def f(name, age): 2 print('I am %s,I am %d' % (name, age)) 3 f('alex', 18) 4 f('alvin', 16) 5 #I am alex,I am 18 6 #I am alvin,I am 16
2、关键字参数:
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
1 def f(name, age): 2 print('I am %s,I am %d' % (name, age)) 3 # f(16,'alvin') #报错 4 f(age=16,name='alvin') 5 #I am alvin,I am 16
3、默认参数:
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果sex没有被传入:
1 def print_info(name, age, sex='male'): 2 print('Name:%s' % name) 3 print('age:%s' % age) 4 print('Sex:%s' % sex) 5 return 6 print_info('alex', 18) 7 print_info('Alin', 16, 'female') 8 # Sex:male 9 # Name:Alin 10 # age:16 11 # Sex:female
4、不定长参数:(非常重要)
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。
例:使用不定长形参*args,完成自加运算。
1 def sum(*args): 2 sum = 0 3 for i in args: 4 sum+=i 5 print(sum) 6 sum(1,2,3,4,5,6)#21
注意: *args可以存放所有未命名的参数变量。而**kwargs会存放命名变量。其中,**kwargs输出的结果是字典形式(键值对)
1 def print_info(**kwargs): 2 print(kwargs) 3 for i in kwargs: 4 print('%s:%s' % (i, kwargs[i])) # 根据参数可以打印任意相关信息了 5 6 return 7 print_info(name='alex', age=18, sex='female', hobby='girl', nationality='Chinese', ability='Python') 8 #{'sex': 'female', 'ability': 'Python', 'hobby': 'girl', 'name': 'alex', 'nationality': 'Chinese', 'age': 18} 9 # sex:female 10 # ability:Python 11 # hobby:girl 12 # name:alex 13 # nationality:Chinese 14 # age:18 15 16 def print_info(name, *args, **kwargs): # def print_info(name,**kwargs,*args):报错 17 18 print('Name:%s' % name) 19 print('args:', args) 20 print('kwargs:', kwargs) 21 22 return 23 print_info('alex', 18, hobby='girl', nationality='Chinese', ability='Python') 24 # print_info(hobby='girl','alex',18,nationality='Chinese',ability='Python') #报错 25 # print_info('alex',hobby='girl',18,nationality='Chinese',ability='Python') #报错 26 27 # Name:alex 28 # args: (18,) 29 # kwargs: {'nationality': 'Chinese', 'ability': 'Python', 'hobby': 'girl'}
形参传递的另一种形式:
1 def f(*args): 2 print(args) 3 f(*[1, 2, 5]) 4 # (1, 2, 5) 5 6 def f(**kargs): 7 print(kargs) 8 f(**{'name': 'alex'}) 9 # {'name': 'alex'}
四、函数的返回值
想获取函数的执行结果,就可以用return语句把结果返回
1 def add(*args): 2 sum=0 3 for i in args: 4 sum+=i 5 print(sum) 6 return 7 a=add(1,5) 8 print(a) 9 # 6 10 # None
1 def foo(): 2 return 9,'asda',2 3 a=foo() 4 print(a) 5 # (9, 'asda', 2)
注意:
1、函数在执行过程中,只要遇到return语句,就会停止执行并返回结果,return语句代表函数的结束。
2、如果未在函数中指定return,那么该函数的返回值为None。
3、return多个对象,python解释器会将这多个对象封装成一个元组作为一个整体结果输出。
五、函数作用域:
5.1 作用域层级:
1、L:local,局部作用域,即函数中定义的变量;
2、E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
3、G:globa,全局变量,就是模块级别定义的变量;
4、B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
5.2 作用域产生:
在python中,只有模块(module),类(class)以及函数(def,lambda)才会引入新的作用域,其它代码块如(if,try,for)不会引入新的作用域。
5.3 global关键字:
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,代码如下:
1 name='lhf' 2 def change_name(): 3 global name #将模块内部局部变量修改为全局变量 4 name='wpq' 5 print('我的名字',name) 6 change_name() 7 print(name) 8 # 我的名字 wpq 9 # wpq
1 name='lhf' 2 def change_name(): 3 # global name 4 name='wpq' 5 print('我的名字',name) 6 change_name() 7 print(name) 8 # 我的名字 wpq 9 # lhf
注意:
1、如果函数内容无global关键字,优先读取局部变量。能读取全局变量,无法对全局变量重新赋值。但是对于可变类型,可对内部元素进行操作。
2、如果函数中由global关键字,变量本质上就是全局变量,可读取赋值。
分类:
一、如果函数内容无global关键字
1、有声明局部变量:
1 name = {"产品经理","项目经理"} 2 def career(): 3 name = "架构师" 4 print("我要做",name) 5 career() 6 # 我要做 架构师
2、无声明局部变量:
1 name = ["产品经理","项目经理"] 2 def career(): 3 name.append('架构师') 4 print("我要做",name) 5 career() 6 # 我要做 ['产品经理', '项目经理', '架构师']
二、函数内容有global关键字:
1、有声明局部变量
1 name = {"产品经理","项目经理"} 2 def career(): 3 global name 4 name = "架构师" 5 print("我要做",name) 6 career() 7 # 我要做 架构师
2、无声明局部变量
1 name = ["产品经理","项目经理"] 2 def career(): 3 global name 4 name.append('架构师') 5 print("我要做",name) 6 career() 7 # 我要做 ['产品经理', '项目经理', '架构师']
错误示例:变量声明放在global前
1 def career(): 2 name='架构师' 3 global name 4 print("我要做",name) 5 career()-------------报错
总结:使用规则:全局变量变量名均大写,局部变量名均小写。
5.4 小结:
(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;
(2)只有模块、类、及函数才能引入新作用域;
(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。
六、函数嵌套程序执行步骤:
1、嵌套函数与作用域:
1 name = 'Allen'#------------------------------1 2 def huangwei():#-----------------------------2 3 name = 'huang'#----------------------4.1 4 print(name)#-------------------------4.2 5 def liuyang():#----------------------4.3 6 name = 'liuyang'#------------4.4.1 7 print(name)#-----------------4.4.2 8 def nulige():#----------------4.4.3 9 name='huzhihua'#-----4.4.5.1 10 print(name)#---------4.4.5.2 11 print(name)#-----------------4.4.4 12 nulige()#--------------------4.4.5 13 liuyang()#---------------------------4.4 14 print(name)#-------------------------4.5 15 print(name)#-------------------------------3 16 huangwei()#--------------------------------4 17 print(name)#-------------------------------5 18 # Allen 19 # huang 20 # liuyang 21 # liuyang 22 # huzhihua 23 # huang 24 # Allen
2、global只改变最外层全局变量,对嵌套作用域变量没有影响
1 name = "alex" 2 def weihou(): 3 name = "chenzhuo" 4 def weiweihou(): 5 global name#----------仅改变最外层全局变量 6 name = "凉凉" 7 weiweihou() 8 print(name) 9 print(name) 10 weihou() 11 print(name) 12 # alex 13 # chenzhuo 14 # 凉凉
3、nonlocal只改变上一层变量(嵌套作用域变量)
1 name = "alex" 2 def weihou(): 3 name = "chenzhuo" 4 def weiweihou(): 5 nonlocal name#-----指上一级变量->chenzhuo,不更改全局变量 6 name = "凉凉" 7 weiweihou() 8 print(name) 9 print(name) 10 weihou() 11 print(name) 12 # alex 13 # 凉凉 14 # alex
七、前向引用:函数即变量。
八、递归函数:在函数内部,可以调用其他函数,如果一个函数在内部调用自身,这个函数就是递归函数。
例1:阶乘运算:
1 def f(n): 2 if n==1: 3 return 1 4 return n*f(n-1) 5 print(f(3)) 6 #6
例2:斐波那契数列:
1 def f(n): 2 if n <= 2: 3 return 1 4 res = f(n-1)+f(n-2) 5 return res 6 print(f(6)) 7 #8
总结:
1、递归函数的优点:定义简单,逻辑清晰。理论上,所有递归函数都可以写成循环方式,但是循环的逻辑不如递归清晰。
2、递归特性:
1、必须有一个明确的结束条件
2、每进入更深一层递归时,问题规模相比上次递归都应有所减少
3、递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
九、重要的内置函数:
1、匿名函数lambda():
1 f=lambda a,b:a+b 2 print(f(2,6)) 3 # 8
2、map()函数:处理列表
1 #对列表元素作加法 2 l=[1,2,4,6,4,6,45] 3 a=list(map(lambda x:x+1,l)) 4 print(a) 5 # [2, 3, 5, 7, 5, 7, 46] 6 7 #对列表元素作减法 8 b=list(map(lambda x:x-1,l)) 9 print(b) 10 # [0, 1, 3, 5, 3, 5, 44] 11 12 #对列表元素作乘方 13 c=list(map(lambda x:x**2,l)) 14 print(c) 15 # [1, 4, 16, 36, 16, 36, 2025] 16 17 #将字符串字母变大写,放在列表内 18 msa='linhaifeng' 19 print(list(map(lambda x:x.upper(),msa))) 20 # ['L', 'I', 'N', 'H', 'A', 'I', 'F', 'E', 'N', 'G'] 21 22 # 将列表中元素全部转化成字符串形式: 23 l=[1,2,3,4,5] 24 print(list(map(str,l))) 25 # ['1', '2', '3', '4', '5']
1 #给列表中的字符串加后缀 2 name=['alex','alvin','albert'] 3 a=map(lambda x:x+'_123',name) 4 print(list(a)) 5 # ['alex_123', 'alvin_123', 'albert_123']
形式:map(处理函数调用,处理对象)
3、filter()函数:对列表值进行筛选。
1 python_teacher=['alex_11','wupeiqi_11','yuanhao','linhaifeng_11'] 2 print(list(filter(lambda n:not n.endswith('11'),python_teacher))) 3 # ['yuanhao']
1 people=[ 2 {'name':'alex','age':100},{'name':'wupeixi','age':1000},{'name':'linhaifeng','age':18} 3 ] 4 res = filter(lambda p:p['age'] <=18,people) 5 print(list(res)) 6 # [{'name': 'linhaifeng', 'age': 18}]
4、reduce()函数:合并序列,得到最终结果
1 from functools import reduce 2 l=[21,45,34,65,67] 3 a=reduce(lambda x,y:x+y,l,100) 4 print(a)
#332
5、总结:
1、map() 处理序列中的每个元素,得到的结果是一个列表,该列表元素的个数及位置与原来一样。
2、filter()遍历序列中的每个元素,判断每个元素得到布尔值,如果是 Ture则留下来。处理对象为序列
people=[
{'name':'alex','age':100},{'name':'wupeixi','age':1000},{'name':'linhaifeng','age':18}
]
res = filter(lambda p:p['age'] <=18,people)
print(list(res))
3、reduce()处理序列,然后把序列进行合并操作
实例:计算列表number =[2, -5, 9, -7, 2, 5, 4, -1, 0, -3, 8]中的正数平均值。

1 number=[2,-5,9,-7,2,5,4,-1,0,-3,8] 2 res=list(filter(lambda x:x>0,number)) 3 i=0 4 sum=0 5 for s in res: 6 sum+=s 7 i+=1 8 a=sum/i 9 print(a) 10 # 5.0
1 from functools import reduce 2 number=[2,-5,9,-7,2,5,4,-1,0,-3,8] 3 res=list(filter(lambda x:x>0,number)) 4 a=reduce(lambda x,y:x+y,res)/len(res) 5 print(a) 6 # 5.0
使用reduce()求阶乘,计算平方:
1 from functools import reduce 2 print (reduce(lambda x,y: x*y, range(1,6))) 3 # 120 4 5 squares = map(lambda x : x*x ,range(9)) 6 print (squares)# <map object at 0x10115f7f0>迭代器 7 print (list(squares))#[0, 1, 4, 9, 16, 25, 36, 49, 64]
十、函数式编程:
1、概念:
函数式编程是一种编程范式,我们常见的编程范式有命令式编程(Imperative programming),函数式编程,常见的面向对象编程是也是一种命令式编程。
而函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式。
函数式编程中的函数这个术语不是指计算机中的函数,而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如y=x*x函数计算x的平方根,只要x的平方,不论什么时候调用,调用几次,值都是不变的。
纯函数式编程语言中的变量也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变的(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。
函数式语言的如条件语句,循环语句也不是命令式编程语言中的控制语句,而是函数的语法糖,比如在Scala语言中,if else不是语句而是三元运算符,是有返回值的。
严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。
函数式编程关心数据的映射,命令式编程关心解决问题的步骤,这也是为什么“函数式编程”叫做“函数式编程”。
1、代码简洁,易懂。
2、无副作用
由于命令式编程语言也可以通过类似函数指针的方式来实现高阶函数,函数式的最主要的好处主要是不可变性带来的。没有可变的状态,函数就是引用透明(Referential transparency)的和没有副作用(No Side Effect)。
文件操作:
操作文件时,一般需要以下步骤:
1、打开文件
2、操作文件
一、打开文件
1 f=open('爱情悬崖',encoding='utf-8') 2 data=f.read() 3 print(data) 4 f.close()
打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。
打开文件的模式有:
- r,只读模式(默认)。
- w,只写模式。【不可读;不存在则创建;存在则删除内容;】
- a,追加模式。【可读; 不存在则创建;存在则只追加内容;】
"+" 表示可以同时读写某个文件
- r+,可读写文件。【可读;可写;可追加】
- w+,无意义
- a+,同a
1、读取文件操作
1 f=open('爱情悬崖','r',encoding='utf-8') 2 data=f.readable() 3 print(data) 4 print(f.readline()) 5 print(f.readline()) 6 print(f.readline()) 7 f.close() 8 # True 9 # 你说我像一个小孩 10 # 11 # 总爱让你猜 12 # 13 # 我说你才像个小孩
f=open('爱情悬崖','r',encoding='utf-8') data=f.readlines() print(data) #文件内容均被放入一个列表内 #['你说我像一个小孩 ', '总爱让你猜 ', '我说你才像个小孩 ', '总要我说才明白 ', '有些事太快 ', '失去了等待 ', '让爱 没了期待 '....
掌握,open(),f.read() f.rendline f.readable()用法
2、写文件操作:
1 f=open('练习写文件','w',encoding='utf-8') 2 f.write('阿达看看打开 ') 3 f.write('水电费师范大学 ') 4 f.write('啊大大侧 ') 5 f.writelines(['adadadada ','adada ']) 6 f.close()
3、追加操作:
1 f=open('练习写文件','a',encoding='utf-8') 2 f.write('ending')
注意: 文件没有修改一说,均是被覆盖。
2、with方法:
为了避免打开文件后忘记关闭,可以通过管理上下文,即:(建议使用此方法打开文件)
1 with open('log','r') as f:
使用该法,当with代码块执行完毕时,内部会自动关闭并释放文件资源。
3、文件修改