高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
1 def test1(a,b,c): 2 print(c(a)+c(b)) 3 4 test1(-1,-4,abs) #把另一个函数当做参数
1 a = lambda x : x*3 #只能写一行,中间不能再加更多的参数,只能进行简单的操作 2 3 #可以写三元运算 4 b = lambda y:4if y < 10 else y
装饰器
装饰器:
1、不修改被装饰函数源代码
2、本身就是一个函数
3、与被装饰函数本身无关,不影响其运行
实现装饰器知识储备:
1、函数既变量
2、高阶函数
3、函数嵌套
高阶函数+嵌套函数===》装饰器
1 import time 2 def aaa(x): #运用高阶函数和函数的嵌套实现装饰器 3 def test(*args,**kwargs): #记得写参数,避免有参数是运行出错 4 start_time = time.time() 5 print(time.strftime('%Y-%m-%d %X')) 6 x(*args,**kwargs) #被装饰函数的运行处 7 stop_time = time.time() 8 print("uesd time:%s" % (stop_time - start_time)) 9 return test #######千万不能忘了return!!!!!!!!! 10 @aaa #想装饰哪个函数,就放在哪个函数的前面 11 def test1(): 12 time.sleep(2) 13 print("123123132") 14 @aaa 15 def test2(c): 16 time.sleep(3) 17 print("--->>",c) 18 test1() 19 test2("sd")
1 log_list=[] 2 log_1,log_2='xyz','abc' 3 def log_in(log_in_1): #设置选择的参数 4 def login(func): #被装饰函数 5 def log(*args, **kwargs): #被装饰函数内的参数 6 if log_in_1 == "file": #设置选项 7 with open("login.txt","r",encoding="utf-8") as log_file: 8 while True: 9 log_line=log_file.readline().strip('\n').split(',') 10 if not log_line == [""]: 11 log_list.append(log_line) 12 else: 13 break 14 user_name = input("username1:").strip() 15 pass_word = input("password1:").strip() 16 count = 0 17 for i in log_list: 18 if user_name ==i[0]and pass_word==i[1]: 19 print("welcome") 20 func(*args, **kwargs) 21 return 1 22 else: 23 if count == log_list.index(log_list[-1]): 24 print("wrong") 25 count +=1 26 elif log_in_1 == "neicun": #设置选项 27 user_name = input("username2:").strip() 28 pass_word = input("password2:").strip() 29 if user_name==log_1 and pass_word == log_2: 30 print("welcome") 31 func(*args, **kwargs) 32 return 2 33 else: 34 print("wrong") 35 36 return log #######千万不能忘了return!!!!!!!!! 37 return login #######千万不能忘了return!!!!!!!!! 38 @log_in(log_in_1='file') #若调用时存在选择,则用最外层参数 39 def test1(): 40 print("123") 41 return 1 #装饰器中必需要加一个返回值成功返回,此处才能返回 42 #因为调用test的时候相当于调用上面的log,而log若无返回值,则test也无返回值,就会打印出none 43 @log_in(log_in_1='neicun') 44 def test2(): 45 print("456") 46 return 2 47 48 49 test1() 50 test2()
生成器:
定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器
作用:
这个yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以再重新调用这个函数,从上次yield的下一句开始执行。
另外,还可通过yield实现在单线程的情况下实现并发运算的效果
1 b=( i*2 for i in range(10)) #形成生成器,省内存 2 print(b) #若不调用,则不会存在于内存中,只有调用时才会现生成 3 4 #b.__next__() 只有此方法可以一个一个 查看 生成器中的数据 5 6 for i in range(5): #若只调用前5个数,则只生成前5个在内存中,后面的都没生成 7 print(i)
1 def fib(x): #用yield会把函数变成生成器 2 n=0 #只能用__next__()执行 3 a=0 4 b=1 5 while n <=x: 6 a,b=b,a+b #赋值语句,解释: 7 yield (a,b) # 代替print 8 n+=1 9 return 1
还可通过yield实现在单线程的情况下实现并发运算的效果
1 import time 2 baozi=["韭菜鸡蛋","青椒肉","牛肉","三鲜","猪肉白菜"] 3 def eater(name): 4 print("%s准备吃了"%name) 5 while True: 6 7 bao_zi=yield #待定的值 8 print("1个%s包子被%s吃了"%(bao_zi,name)) 9 10 def productor(name): 11 b=eater("邢韬") 12 b2 = eater("丽丽") 13 print("%s开始准备做包子啦"%name) 14 b.__next__() 15 b2.__next__() 16 for i in baozi: 17 time.sleep(1) 18 print("%s做好了2个%s馅包子,一人一个"%(name,i)) 19 b.send(i) 20 b2.send(i) 21 22 productor('厨师')
异常探测
1 、用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中
2 、当__next__()超出生成器最大长度是,会出现异常
3 、当不知道生成器长度时,可使用抓住异常的方法去尝试
1 g = fib(6) 2 3 while True: 4 try: #异常探测 5 x = next(g) #不出错会无限循环 6 print('g:', x) 7 except StopIteration as e: #出错执行这里 8 print('Generator return value:', e.value) 9 break
迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
我们已经知道,可以直接作用于for
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
可以使用isinstance()
判断一个对象是否是Iterable
对象:
1 from collections import Iterator,Iterable #调用模块 2 3 Iterator([],Iterable) 4 #判断是否为可迭代对象(可直接作用于FOR循环的对象如列表、元组等) 5 6 isinstance((x for x in range(10)),Iterator) 7 #判断是否为迭代器对象(可以被__next__()函数调用并不断返回下一个值的对象称为迭代器:Iterator) 8 9 a=iter([1,2,3]) #把可迭代对象变为迭代器
内置方法
1 all([-1,1,2,3]) #如果可迭代对象中所有元素都为真(非0即是真),则返回True 2 any([0,1]) #如果可迭代对象中任一元素为真(非0即是真),则返回True 3 ascii([88]) #变成字符串str格式 4 bin(8) #十进制转2进制 5 bool(0) #判断真假
1 a=bytearray("abcde",encoding="utf-8") 2 print(a[0]) #打印ascii码中的位置 3 a[1]=110 #替换只能用ascii码替换 4 print(a) 5 ————————分割———————— 6 def test():pass 7 8 callable(test) #判断是否可调用(后面是否可以加括号) 9 10 ————————分割———————— 11 12 chr(80) #返回ascii码对应的值,必须是数字 13 ord("p") #返回在ascii码中的位置 14 exec() #可执行字符串,可以算复杂的 15 ——————————分割———————— 16 s=1 17 eval("s+1") #运行字符串,只能算简单的 18 ——————————分割—————————— 19 dir(b) #查看可执行方法
1 filter(lambda x:x>4,range(10)) #变成迭代器了,并只选择合格的值 2 3 d = map(lambda x:x*x,range(10)) 4 #也变成迭代器了,按方法输出所有的值,不考虑判断等等 5 6 ——————————分割———————————— 7 e=frozenset([1,2,3,4,5,6,7]) #冻结集合,使其不可变 8 9 globals() #整个文件所有变量变成键值的形式 10 locals() 11 12 max(1,2,3) #返回最大值 13 14 min(1,2,3) #返回最小值 15 16 oct(16) #8进制 17 18 pow(2,8) #幂,x的y次方 19 20 round(1.22577,2) #对X四舍五入Y位 21 22 range(0,20)[slice(2,5)] #切片 == range(0,20)[2:5]
1 g={1:444,2:3231,3:213323,4:123213,5:223,6:31233} 2 3 sorted(g.items()) #根据键对字典进行排序 4 5 sorted(g.items(),key=lambda x:x[1]) #把KEY变成值,就可以根据值来排序了 6 7 ——————————分割—————————— 8 o=[1,2,3,4] 9 p=["a","b","c","d"] 10 for i in zip(o,p): #一一对应 11 print(i)
软件目录结构规范
Foo/ #项目名称
|-- bin/ #可执行文件目录
| |-- foo #可执行文件 #启动时调用main.py主程序
|
|-- foo/ #主程序目录
| |-- tests/ #测试
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py #包
| |-- main.py #程序主入口
|
|-- docs/ #文档
| |-- conf.py
| |-- abc.rst
|
|-- setup.py #安装
|-- requirements.txt #依赖关系
|-- README
详细参考 HTTP://WWW.blogs.com/alex3714/articles/5765046.HTML
简要解释一下:
1 bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
2 foo/: 存放项目的所有源代码。
(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。
(2) 其子目录tests/存放单元测试代码;
(3) 程序的入口最好命名为main.py。
3 docs/: 存放一些文档。
4 setup.py: 安装、部署、打包的脚本。
5 requirements.txt: 存放软件依赖的外部Python包列表。
6 README: 项目说明文件。
除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,Archangel.txt文件等,我没有列在这里,因为这些东西主要是项目开源的时候需要用到。
关于README的内容
这个我觉得是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。
它需要说明以下几个事项:
1 软件定位,软件的基本功能。
2 运行代码的方法: 安装环境、启动命令等。
3 简要的使用说明。
4 代码目录结构说明,更详细点可以说明软件的基本原理。
5 常见问题说明。
我觉得有以上几点是比较好的一个README。在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。
可以参考Re dis源码中read me的写法,这里面简洁但是清晰的描述了Re dis功能和源码结构。