一、自定义函数
一、函数概念
1、什么是函数:函数就是封装一个功能。(程序中如果没有函数的引用,会产生重复代码多,可读性差的特点。)
2、函数的定义:def 关键词开头,空格之后接函数名称和圆括号()
l1 = [1,2,3,4] def my_len(): # def 关键字 定义一个函数 # my_len 函数名书写规则与变量一样 # def与函数名中间一个空格 # 函数名():加上冒号 # 函数体 count = 0 for j in l1: count += 1 print(count) my_len()
l1 = [1,2,3,4] def my_len(): count = 0 for j in l1: count += 1 return count print(my_len()) # 函数的返回值: # 写函数,不要在函数中写print() # return # 1、在函数中,遇到return结束函数。 # 2、将返回值给函数的调用者。 # 无 return = return None # return 1个值 该值是什么,就直接返回给函数的调用者,函数名() # return 多个值,将多个值放到一个元组中,返回给函数的调用者。
二、函数的传参
函数分为形参和实参:
形参:形式参数,不代表实际的变量。
实参:实际参数,带入形参中的变量。
形参传参:1、位置传参。按顺序,一一对应。
2、默认参数。传参则覆盖,不传则默认,默认参数永远在位置参数的后面。
形参传参:1、位置传参。按顺序,一一对应。
2、关键字传参,不按顺序,一一对应。
3、混合传参,关键字参数永远在位置参数的后面。
形参传递顺序:位置参数,*args,默认参数,**kwargs
def test(a, *args, **kwargs): print(a) # 1 print(args) # (2, 3) print(kwargs) # {'e': 5, 'd': '4'} test(1, 2, 3, d='4', e=5) # 1还是参数a的值,args表示剩余的值,kwargs在args之后表示成对键值对。
# * 魔法运用 def func(*args): print(args) l1 = [1,2,30] l2 = [1,2,33,21,45,66] tu = (1,2,3) func(1,2,30,1,2,33,21,45,66) # (1, 2, 30, 1, 2, 33, 21, 45, 66) func(*'qweqrfdsaf') # ('q', 'w', 'e', 'q', 'r', 'f', 'd', 's', 'a', 'f') func(*{'name':'alex',"age":12}) # ('name', 'age') func(*l1,*l2) # (1, 2, 30, 1, 2, 33, 21, 45, 66) def func(*args): print(args) func(1,2,3,10,20,80) # (1, 2, 3, 10, 20, 80) def func(**kwargs): print(kwargs) dic1 = {'name1':'alex','age1':46} dic2 = {'name':'老男孩','age':56} func(**dic1,**dic2) # {'age1': 46, 'name1': 'alex', 'name': '老男孩', 'age': 56} # 在函数的调用执行时, # *可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args。 # **字典,代表打散,将所有键值对放到一个kwargs字典里。 # 在函数定义时, *args,**kwargs代表的是聚合。 def func(*args,**kwargs): print(args) print(kwargs) dic1 = {'name1':'alex','age1':46} dic2 = {'name':'老男孩','age':56} func(*[1,2,3,4],*'asdfsad',**dic1,**dic2) # (1, 2, 3, 4, 'a', 's', 'd', 'f', 's', 'a', 'd') # {'name': '老男孩', 'name1': 'alex', 'age': 56, 'age1': 46}
三、函数有用信息
def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) return True func1() # 666 print(func1.__name__) # func1 print(func1.__doc__) # 显示注释内容
二、命名空间和作用域
一、命名空间
命名空间的本质:存放名字与值的绑定关系
命名空间一共分为三种:
全局命名空间:代码在运行伊始,创建的存储“变量名与值的关系”的空间
局部命名空间:在函数的运行中开辟的临时的空间
内置命名空间:存放了python解释器
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值:在局部调用:局部命名空间->全局命名空间->内置命名空间
在全局调用:全局命名空间->内置命名空间
二、作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域(globals):包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域(locals):局部名称空间,只能在局部范围内生效
global关键字
#global # 1,在局部空间内,声明一个全局变量 def func1(): global name name = '老男孩' print(name) # 老男孩 func1() print(name) # 老男孩 # 2,在局部空间内改变一个全局变量 a = 4 def func1(): global a # 5 a = 5 func1() print(a)
nolocal关键字
#nonlocal # 1,不能修改全局变量。 #在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改, # 并且引用的哪层,从那层及以下此变量全部发生改变。 a = 4 def func1(): b = 6 def func2(): b = 666 print(b) # 666 func2() print(b) # 6 func1() b = 4 def func1(): b = 6 def func2(): nonlocal b b = 666 print(b) # 666 func2() print(b) # 666 print(b) # 4 func1()
三、函数名的应用
# 函数名是函数的名字,本质:变量,特殊的变量。 # 1,单独打印函数名 <function func1 at 0x0000000000872378> def func1(): print(666) print(func1) # <function func1 at 0x0000000000872378> a = 6 print(a) # 6 # 2、函数名的赋值 def func2(): print(666) f = func2 f() # 666 # 3、函数名可以作为容器类数据的元素 def f1(): print(1211) def f2(): print(1222) def f3(): print(1233) def f4(): print(1233) l1 = [f1, f2, f3, f4] for i in l1: i() # 4、函数名可以作为参数 a = 1 def f1(x): print(x) # 1 f1(a) def f1(): print(666) def f2(x): # x = f1 x() # f1() f2(f1) # 5、函数名可以作为函数的返回值 def wraaper(): def inner(): print(666) return inner ret = wraaper() # inner ret() # inner()
三、闭包和装饰器
一、闭包
闭包:就是内层函数对外层函数(非全局)变量的引用。
闭包:当函数开始执行时,如果遇到闭包,他又一个机制,他会永远开辟一个内存空间,将闭包中的额变量等值放入其中,不会随着函数的执行完毕而消失。
判断是不是闭包:内层函数名.__closure__ 结果是:cell...就是闭包
name = '老男孩' def wraaper2(n): # n = '老男孩' def inner(): print(n) # 老男孩 inner() print(inner.__closure__) # (<cell at 0x000001E3F9123B28: str object at 0x000001E3F9010F30>,) wraaper2(name)
二、装饰器
开放封闭原则:
1、对扩展是开放的
2、对修改是封闭的
装饰器主要功能和装饰器固定结构:在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器固定格式
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner
带参数的装饰器
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func()
多个装饰器装饰同一个函数
def wrapper1(func): def inner(): print('wrapper1 ,before func') # 第二步 func() print('wrapper1 ,after func') # 第四步 return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') # 第一步 func() print('wrapper2 ,after func') # 第五步 return inner @wrapper2 @wrapper1 def f(): print('in f') # 第三步 f()
四、迭代器和生成器
一、迭代器
可迭代协议:可以被迭代要满足的要求,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代,内部实现了__iter__方法
迭代协议:必须拥有__iter__方法和__next__方法
迭代器的好处:
1、节省内存空间。
2、满足惰性机制。
3、不能反复取值,不可逆。
可迭代计算过程:
1、将可迭代对象转化成迭代器
2、内部使用__next__方法取值
3、运用了异常处理去处理报错。
l2 = [1, 2, 3, 4, 5, 6, 7, 8] l2_obj = l2.__iter__() while True: try: i = l2_obj.__next__() print(i) except Exception: break
二、生成器
生成器:生成器本质上是迭代器。
初始生成器:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
生成器函数定义:
1、一个包含yield关键字的函数就是一个生成器函数
2、next 和send 功能一样,都是执行一次,send获取下一个值可以给上一个yield赋值。
使用send的注意事项:第一次使用生成器的时候,使用next获取下一个值,最后一个yield不能接受外部的值
def generator(): print(123) # 123 content = yield 1 print(content) # hello print(456) #456 yield 2 g = generator() g.__next__() g.send('hello')
三、列表推导式和生成器表达式
1、列表推导式:用列表推导式能够构建的任何列表,用别的都可以构建,一目了然,占内存。
l2 = [i*i for i in range(1,11)] print(l2) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表,不易看出,节省内存。
l_obj = ('python%s期' % i for i in range(1,12)) print(l_obj) # <generator object <genexpr> at 0x000001AAF0AEBDB0> print(l_obj.__next__()) # python1期 print(l_obj.__next__()) # python2期 print(l_obj.__next__()) # python3期
总结:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可 以直接这样计算一系列值的和:
五、内置函数
3.x版本python共提供68种内置函数
详细内容见http://www.cnblogs.com/qiujie/p/8982773.html,内置函数思维导图:https://www.processon.com/view/link/5ae949b8e4b09b1bf63730c4
六、匿名函数
匿名函数:为了解决那些功能很简单的需求而设计的一句话函数。
def calc(n): return n*n print(calc(10)) cal = lambda n:n*n print(cal(10))
上面是我们对calc这个匿名函数的分析,下面给出了一个关于匿名函数格式的说明
函数名 = lambda 参数 :返回值 #参数可以有多个,用逗号隔开 #匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值 #返回值和正常的函数一样可以是任意数据类型
我们可以看出,匿名函数并不是真的不能有名字。
匿名函数的调用和正常的调用也没有什么分别。 就是 函数名(参数) 就可以了~~~
匿名函数与内置函数举例:
l=[3,2,100,999,213,1111,31121,333] print(max(l)) dic={'k1':10,'k2':100,'k3':30} print(max(dic)) print(dic[max(dic,key=lambda k:dic[k])]) # 31121 # k3 # 100 res = map(lambda x:x**2,[1,5,7,4,8]) for i in res: print(i) # 1 # 25 # 49 # 16 # 64 res = filter(lambda x:x>10,[5,8,11,9,15]) for i in res: print(i) # 11 # 15
七、递归函数
递归:一个函数在内部调用自己的函数称为递归,递归的次数在python是有限制的,默认递归次数是997次。
# 输出斐波那契第n个数 def fib(n): if n==1 or n==2: return 1 return fib(n-1)+fib(n-2)