1 什么是函数? 函数就是具备某一个功能的工具, ----需要工具时,需要提前准备好,然后拿来就用且可以重复使用 所以 函数需要先定义,再使用
2 为什么要用函数?
1,代码的组织结构不清晰,可读性差 2,遇到重复的功能只能重复编写实现代码,代码冗余 3,功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大
3 函数的分类:内置函数与自定义函数 内置函数:python解释器已经为我们定义好了的函数 自定义函数:我们自己根据需求,事先定制好的我们自己的函数,来实现某种功
4 如何自定义函数 语法 def 函数名(参数1,参数2,参数3.......): """注释""" 函数体 return 返回的值 # 函数名要能反映其意义 函数使用的原则:先定义,再调用 函数即"变量","变量"必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名 函数的使用,必须遵循原则:先定义,后调用 ###我们在使用函数时,一定要明确区分定义阶段和调用阶段### #定义阶段 def foo(): print('from foo') bar() def bar(): print('from bar') #调用阶段 foo() 定义有参数函数,及有参函数的应用场景 有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度等 def tell_tag(tag,n): #有参数 print (tag*n) 定义无参数函数,及无参函数的应用场景 无参:应用场景仅仅只是执行一些操作,比如用户交互,打印 def tell_msg(): #无参数 print ('hello world') 定义空函数,及空函数的应用场景 设计代码结构 #结论: #1,定义是无参,意味着调用时也无需传入参数 #2,定义是有参,意味着调用时则必须传入参数 函数在定义阶段: 只检测语法,不执行代码 --语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道 5 调用函数 如何调用函数 函数的调用:函数名加括号 1,先找到名字 2,根据名字调用代码 函数的返回值 无return--->None return 1个值->返回1个值 return 逗号分隔多个值 -->返回元组 什么时候该有返回值: 调用函数,经过一系列的操作,最后拿到一个明确的结果,则必须要有返回值 通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果 什么时候不需要有返回值: 调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值 通常无参函数不需要有返回值 函数调用的三种形式 1,语句形式:foo() 2,表达式形式:3*len(’hello‘) 3,当中另外一个函数的参数:range(len(’hello‘)) 函数参数的应用: 形参和实参 形参即变量名,实参即变量名,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定 位置参数:按照从左到右的顺序定义的参数 位置形参:必选参数 位置实参:按照位置给形参传值
关键字参数:按照key=value的形式定义的实参 无需按照位置为形参传值 注意的问题: 1,关键字实参必须在位置实参后面 2,对同一个形参不能重复传值 默认参数:形参在定义时就已经为其赋值 可以传值也可以不传值,经常需要变的参数定义成位置形参,变化较小的参数定义成默认参数(形参) 注意的问题: 1,只在定义的时候赋值一次 2,默认参数的定义应该在位置形参右边 3,默认参数通常应该定义成不可变类型 可变长参数: 可变长指的是实参值得个数不固定 而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整的存放它们, 分别是 *args,**kwargs(args,kwargs只是约定俗成的表示,没有特殊意义)
===========*args=========== def foo(x,y,*args): print(x,y) print(args) foo(1,2,3,4,5) def foo(x,y,*args): print(x,y) print(args) foo(1,2,*[3,4,5]) def foo(x,y,z): print(x,y,z) foo(*[1,2,3]) ===========**kwargs=========== def foo(x,y,**kwargs): print(x,y) print(kwargs) foo(1,y=2,a=1,b=2,c=3) def foo(x,y,**kwargs): print(x,y) print(kwargs) foo(1,y=2,**{'a':1,'b':2,'c':3}) def foo(x,y,z): print(x,y,z) foo(**{'z':1,'x':2,'y':3}) ===========*args+**kwargs=========== def foo(x,y): print(x,y) def wrapper(*args,**kwargs): print('====>') foo(*args,**kwargs)
命名关键字参数:
* 后定义的参数,必须被传值(有默认值得除外),且必须按照关键字实参的形式传递
可以保证,传入的参数中一定包含某些关键字
def foo(x,y,*args,a=1,b,**kwargs): print(x,y) print(args) print(a) print(b) print(kwargs) foo(1,2,3,4,5,b=3,c=4,d=5) 结果: 1 2 (3, 4, 5) 1 3 {'c': 4, 'd': 5
6 高阶函数(函数对象) 函数是第一类对象,即函数可以当做数据传递 1,函数可以被引用 2,函数可以当做参数传递 3,函数的返回值可以是函数 4,函数可以当做容器类型的元素 利用这些特性,可以取代多分支的if
1 def foo(): 2 print('foo') 3 4 def bar(): 5 print('bar') 6 7 dic={ 8 'foo':foo, 9 'bar':bar, 10 } 11 while True: 12 choice=input('>>: ').strip() 13 if choice in dic: 14 dic[choice]()
7 函数嵌套 函数的嵌套调用
1 def max(x,y): 2 return x if x > y else y 3 4 def max4(a,b,c,d): 5 res1=max(a,b) 6 res2=max(res1,c) 7 res3=max(res2,d) 8 return res3 9 print(max4(1,2,3,4))
8 作用域与名称空间 名称空间:存放名字的地方,三种空间:内置名称空间,全局名称空间,局部名称空间 存放的是名字和内存地址的对应关系
名称空间的加载顺序
python test.py #1、python解释器先启动,因而首先加载的是:内置名称空间 #2、执行test.py文件,然后以文件为基础,加载全局名称空间 #3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
名字的查找顺序 局部名称空间--全局名称空间--内置名称空间 注意:在全局无法查看局部的,在局部可以查看全局的作用域:作用域即范围 -全局范围:(内置名称空间与全局名称空间属于该范围):全局存活,全局有效 -局部范围:(局部名称空间属于该范围):临时存活,局部有效 查看作用域: globals(),locas()
1 LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__ 2 locals 是函数内的名字空间,包括局部变量和形参 3 enclosing 外部嵌套函数的名字空间(闭包中常见) 4 globals 全局变量,函数定义所在模块的名字空间 5 builtins 内置模块的名字空间
闭包函数 内部函数包含对外部作用域而非全局作用域的引用
1 def index(url): 2 def get(): 3 return urlopen(url).read() 4 return get
1 #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域 2 #应用领域:延迟计算(原来我们是传参,现在我们是包起来) 3 from urllib.request import urlopen 4 5 def index(url): 6 def get(): 7 return urlopen(url).read() 8 return get 9 10 baidu=index('http://www.baidu.com') 11 print(baidu().decode('utf-8'))
9 装饰器 为什么要用装饰器? 开放封闭原则:对修改封闭,对扩展开放 什么是装饰器? 装饰器本身是任意可调用对象,被装饰着也可以是任意可调用对象 装饰器的原则: 1,不修改被装饰对象的源代码 2,不修改被装饰对象的调用方式 3,在遵循1和2的前提下,为被装饰对象添加新功能 装饰器的基本语法:(任何装饰器都可以套用)
def foo(func): def wrappers(*args,**kwargs): res = func() return res return wrappers
无参装饰器
import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer def foo(): time.sleep(3) print('from foo') foo()
有参装饰器
def auth(driver='file'): def auth2(func): def wrapper(*args,**kwargs): name=input("user: ") pwd=input("pwd: ") if driver == 'file': if name == 'egon' and pwd == '123': print('login successful') res=func(*args,**kwargs) return res elif driver == 'ldap': print('ldap') return wrapper return auth2 @auth(driver='file') def foo(name): print(name) foo('egon')
10 迭代器与生成器及协程函数 1,迭代器就是迭代的工具,迭代就是一个重复的过程,每次重复就是一次迭代,并且每次迭代的结果都是下一次迭代的初始值 2,为什么要有迭代器? 对于没有索引的数据类型,迭代器提供了一种不依赖索引的迭代方式 3,可迭代对象 内置有__iter__方法的对象,即obj.__iter__ 可迭代对象:字符串,列表,元组,字典,集合,文件 4,迭代器对象 可迭代对象执行__iter__得到的结果就是迭代器对象 迭代器对象指的是既内置有__iter__又内置有__next__方法的对象 文件类型是迭代器对象
dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() #可迭代对象执行__iter__方法得到的结果就是迭代器对象 #迭代器对象内置有__iter__方法和__next__方法 iter_dic.__iter__() id iter_dic # 迭代器执行__iter__()得到的仍然是迭代器本身 print(iter_dic.__next__()) print(iter_dic.__next__()) print(iter_dic.__next__()) #等同于next(iter_dic) #迭代对象有几个值就需要执行几次,直到没有值可取 print(iter_dic.__next__()) #抛出异常StopIteration,标志迭代对象的值已经全部取出
基于for循环,我们可以实现不依赖索引取值 1 dic={'a':1,'b':2,'c':3} 2 for k in dic: 3 print(dic[k] for循环工作原理 1,执行in后的对象__iter__()方法,得到一个迭代器对象 2,执行__next__方法,将得到的值赋值变量,然后执行循环体代码 3,重复过程2,直到捕捉到异常StopIteration
迭代器的优缺点:
优点:提供了一种不依赖索引的迭代方式
缺点:无法获取长度
只能一直往前取,无法往后取生成器 函数内包含有yield关键字 再调用函数,就不会执行函数体代码,拿到的返回值就是一个生成器对象 注意::生成器本质就是迭代器,也就是说迭代器的用法就是生成器的用法 11 三元运算,列表解析、生成器表达式 三元运算: 格式: 为真时的结果 if 判断条件 else 为假时的结果 例子: print(1 if 5>3 else 0) 列表解析(列表推导式) 基本形式:[表达式 for 参数 in 可迭代对象] 或者 [表达式 for 参数 in 可迭代对象 if 条件] 实例
1 l = [] 2 for i in range(100): 3 l.append('egg%s' %i) 4 print i 5 6 #不带if条件 7 l = ['agg%s' %i for i in range(100) ] 8 9 #带if条件 10 l = ['agg%s' %i for i in range(100) if i>10]
生成器表达式
将列表推导式的中括号改为小括号即可
l = ('egg%s' %i for i in range(100) if i>10) print(next(l)) 注意:得到的结果为迭代器
12 函数的递归调用 递归调用是函数嵌套调用的一种特殊形式,函数在调用时,直接或间接调用了自身就是递归调用 递归的两个阶段: 回溯:往前搜索,以达到目标 注意:一定要在满足某个条件的情况下结束回溯,否则就是无限递归 递推:往回推
1 def age(n): 2 if n == 1: 3 return 1 4 else: 5 return age(n-1)+2 6 7 print(age(5))
递归总结: 递归必须有一个明确的结束条件 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 python没有尾递归优化,但是设置了最大递归层数
13 内置函数 内置函数就是python解释器定义好的函数
reduce(func,iterable) 从可迭代系列中循环取值,参与第一个函数参数的计算,最后得到一个结果
reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
bytes()将unicode指定编码后转化为bytes类型
chr()返回值是传入整数对应的ascii字符
divmod()将除数和余数的运算结果结合起来,返回一个包含商和余数的元组(a//b,a%b)
>>>divmod(7, 2) (3, 1) >>> divmod(8, 2) (4, 0) >>> divmod(1+2j,1+0.5j) ((1+0j), 1.5j)
enumerate()将一个可遍历的数据对象组合为一个索引序列,同时列出数据个数据下标,一般用在for循环
>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter'] >>> list(enumerate(seasons)) [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
eval()执行一个字符串表达式,并返回表达式的值
>>>x = 7 >>> eval( '3 * x' ) 21 >>> eval('pow(2,2)') 4 >>> eval('2 + 2') 4 >>> n=81 >>> eval("n + 4") 85
filter(func,iterable)函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表
import math def is_sqr(x): return math.sqrt(x) % 1 == 0 newlist = filter(is_sqr, range(1, 101)) print(newlist)
id() 返回参数的内存地址序号
input()获取输入
iter(object)生成迭代器
len()返回参数长度
map(func,iterable)第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数 [1, 4, 9, 16, 25] >>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]) [3, 7, 11, 15, 19]
max()返回给定参数的最大值,参数可以是系列
egon male 18 3000 alex male 38 30000 wupeiqi female 28 20000 yuanhao female 28 10000 with open('db.txt') as f: items=(line.split() for line in f) info=[{'name':name,'sex':sex,'age':age,'salary':salary} \ for name,sex,age,salary in items] print(max(info,key=lambda dic:dic['salary'])) max(iterable, key, default) 求迭代器的最大值,其中iterable 为迭代器,max会for i in … 遍历一遍这个迭代器,然后将迭代器的每一个返回值当做参数传给key=func 中的func(一般用lambda表达式定义) ,然后将func的执行结果传给key,然后以key为标准进行大小的判断
min()返回给定参数的最小值,参数可以是系列
ord()返回给定参数的十进制数
>>>ord('a') 97 >>> ord('b') 98 >>> ord('c') 99
sorted()对所有可迭代的对象进行排序操作。
sort 与 sorted 区别: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。 list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
iterable -- 可迭代对象。 cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。 key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
>>>a = [5,7,6,3,4,1,2] >>> b = sorted(a) # 保留原列表 >>> a [5, 7, 6, 3, 4, 1, 2] >>> b [1, 2, 3, 4, 5, 6, 7] >>> L=[('b',2),('a',1),('c',3),('d',4)] >>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利用cmp函数 [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> sorted(L, key=lambda x:x[1]) # 利用key [('a', 1), ('b', 2), ('c', 3), ('d', 4)] >>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] >>> sorted(students, key=lambda s: s[2]) # 按年龄排序 [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] >>> sorted(students, key=lambda s: s[2], reverse=True) # 按降序 [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] >>>
14 面向过程编程
#1、首先强调:面向过程编程绝对不是用函数编程这么简单,面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序 #2、定义 面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式 #3、优点:复杂的问题流程化,进而简单化 #4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身 #5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd #6、举例 流水线1: 用户输入用户名、密码--->用户验证--->欢迎界面 流水线2: 用户输入sql--->sql解析--->执行功能
来源:https://www.cnblogs.com/guodengjian/p/8710617.html