1.装饰器
定义:本质是一个函数,(装饰其他函数)就是为其他函数添加附加功能
原则:不能修改被装饰函数的源代码,不能修改被装饰函数的调用方式
实现装饰器的知识储备:
函数即“变量”。每当定义一个函数时,函数的名字就是变量的名字,函数体就是变量的内容
'''errordef foo(): print("in the foo") bar()foo()''''''OKdef bar(): print("in the bar")def foo(): print("in the foo") bar()foo()''''''OKdef foo(): print("in the foo") bar()def bar(): print("in the bar")foo()''''''errordef foo(): print("in the foo") bar()foo()def bar(): print("in the bar")'''
高阶函数:
a:把一个函数名当作实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加附加功能)
b:返回值中包含函数名(在不修改函数的调用方式)
import time'''把一个函数名当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为其添加功能)def bar(): time.sleep(3) print("in the bar")def test1(func): start_time = time.time() func() stop_time = time.time() print("the func run time is %s"%(stop_time-start_time))test1(bar)''''''返回值中包含函数名(不修改函数的调用方式)def bar(): time.sleep(0.1) print("in the bar")def test2(func): print(func) return funcbar = test2(bar) #==》@test2bar()'''
嵌套函数:
嵌套函数+高阶函数=》装饰器
import time#嵌套函数,在一个函数的函数体内定义另一个函数#被嵌套函数的作用域是嵌套它的函数的内部def foo(): print("in the foo") def bar(): print("in the bar") bar()foo()def auth(func): def wrapper(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return wrapper@auth #相当于test=auth(test)-->test=wrapperdef test(): time.sleep(10) print("in the tset")test()
装饰器完整程序示例:
测试时间
import timedef timer(func): #timer(test1) func = test1 def deco(): start_time = time.time() func() #func = test1 stop_time = time.time() print("the func run time is %s"%(stop_time - start_time)) return deco@timer #test1=timer(test1)def test1(): time.sleep(3) print("in the test1")@timer #test2=timer(test2)def test2(): time.sleep(2) print("in the test2")#test1 = timer(test2)#test2 = timer(test2)test1()test2()
验证登陆
import timeuser_name = "Mr Wu"user_passwd = "187847"def auth(auth_type): print("by the %s"%auth_type) def out_wrapper(func): def wrapper(*args,**kwargs): if auth_type == "local": name = input("input your usernmae:") passworld = input("input your passworld:") if name == user_name and passworld == user_passwd: func(*args,**kwargs) else: exit("invalid input!") elif auth_type == "ldt": print("老子不会!操!") return wrapper return out_wrapper@auth(auth_type="local")#相当于@out_wrapper-->home = out_wrapper(home)-->home = wrapperdef home(): print("welcome to home page!")@auth(auth_type="ldt")def bbs(): print("welcome to bbs page!")home()bbs()
2.迭代器与生成器
生成器:
列表生成式:通过列表生成式,我们可以直接创建一个列表,但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅需要很大的存储空间,如果我们仅仅需要访问前面的几个元素,那后面绝大多数元素占用的空间都白白浪费了。
生成器:所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环过程中不断推算出后续元素呢,这样就不必创建完整的list,从而节省大量的空间。在python中,这种一边循环一边计算的机制i,称为生成器:generator
创建一个generator的两种方法:
(1)只要把一个列表生成式的[]改为(),就创建了一个generator。只有在调用时才会生成相应的数据,只能记住当前的位置,只有一个_next_()方法。(2)带有yield的generator function(生成器函数)
#第一种生成器方法==》通过列表生成式改造counting = (i for i in range(100))for i in counting: print(i)#第二种成器方法==》通过函数生成def counting(max): n = 0 while n
迭代器:
可以被next()函数调用并不断返回下一个值,直到没有数据时抛出StopIteration错误的对象称为迭代器:Iterator
可以直接作用域for循环的数据类型有以下几种:(1)集合数据类型,如list、tuple、dict、set、str(2)generator,包括生成器和带yield的generator function
这些可以直接作用于for循环的对象称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否是Iterable对象
生成器(generator)都是Iterator对象,但是list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str变成Iterator可以使用iter()函数
为什么list、dict、str等数据类型不是Iterator?
这是因为python的Iterator表示的是一个数据流(没有一个确定的结束值)。Iterator的对象可以被next()函数调用,直到抛出Stopiteration错误。可以把这个数据看做是一个有序序列,但我们却不能知道序列的长度,只能通过next()函数实现按需计算下一个数据,所以Iterator的计算时惰性的,只有在需要返回下一个数据时才会进行计算。Iterator甚至可以表示一个无限大的数据流,例如全体自然数,而使用list是永远不可能存储全体自然数的
程序示例:
python中的for循环本质上就是通过不断调用next()函数实现的:for i in [1,2,3,4,5]: print(i)#完全等价于以下程序:it = iter([1,2,3,4,5])while True: try: #获得下一个值 x = next(it) except StopIteration: #遇到StopIteration就退出循环 break
通过yield实现在单线程的情况下实现并发运算的效果
#吃包子--做包子--》生产--消费流程import timedef consumer(name): print("%s 准备吃包子啦!"%name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了!"%(baozi,name))#c = consumer("alex")#c.__next__()#b1 = "韭菜馅"#c.send(b1) #调用生成器,同时给yield传值def producer(name): c = consumer("A") c2 = consumer("B") c.__next__() c2.__next__() print("老子开始准备做包子啦!") for i in range(10): time.sleep(0.5) print("做了两个包子!") c.send(i) c2.send(i)producer("alex")
3.内置方法
print(all([0,-5,3])) #如果Iterable内部元素都为真,返回True,否则返回Falseprint(any([0,-4,5])) #如果Iterable内部有一个元素为真,返回True,否则(Iterable为空)返回Falsea = ascii([1,2,"开外挂"]) #把列表变成了一个字符串print(type(a),[a]) #["[1, 2, '\\u5f00\\u5916\\u6302']"]print(bin(1)) #将数字转换为二进制print(bool(0)) #判断真假 True、Falsea = bytes("abcde",encoding="utf-8")#字节print(a.capitalize(),a) #b'Abcde' b'abcde'b = bytearray("abcde",encoding="utf-8")#字节数组print(b) #bytearray(b'abcde')b[1] = 50print(b) #bytearray(b'a2cde')print(callable([])) #判断是否可以调用print(chr(98)) #将ASCII码转换为字符print(ord("a")) #将字符转换为ASCII码print(divmod(5,2)) #返回商和余数(2, 1)#filter:对每个值进行过滤后返回结果形成列表rest = filter(lambda n:n<5,range(10))for i in rest: print(i)#map:对每个值进行处理后返回结果形成列表res = map(lambda n:n*n,range(10))for i in res: print(i)import functoolsres = functools.reduce(lambda x,y:x*y,range(1,10))#阶乘print(res)a = frozenset([1,2,3,4,5,6,3,3,3,3])#不可变集合print(a)print(globals())#把当前文件下的所有变量及其方法取出来形成一个字典print(hash("alex")) #将字符串映射成数字(哈希)#help("time") #查看模块的帮助文档print(hex(123)) #将一个数字转换为十六进制print(len("abc123"))#返回字符串的长度def test(): local_var = 333 print(locals())test() #locals()打印局部变量print(globals().get("local_var")) #error,globals()打印全局变量print(max([1,2,3,4,5])) #返回列表中的最大值print(min([1,2,3,4,5])) #返回列表中的最小值print(oct(10)) #将一个数字转为八进制print(pow(3,4)) #计算某个数字的多少次幂print(round(1.4321,4)) #保留多少位小数a = {6:2,8:0,1:4,-5:6,99:11,4:22}#print(sorted(a.items()))#排序print(sorted(a.items(),key = lambda x:x[1]))a = [1,2,3,4,5]b = ["a","b","c","d"]for i in zip(a,b): print(i) #(1, 'a') #(2, 'b') #(3, 'c') #(4, 'd')__import__("decorator1")
compile、eval、exec、single
#compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)'''说明: 1. 将source编译为代码或者AST对象。代码对象能够通过exec语句来执行或者eval()进行求值。 2. 参数source:字符串或者AST(Abstract Syntax Trees)对象。即需要动态执行的代码段。 3. 参数 filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。当传入了source参数时,filename参数传入空字符即可。 4. 参数mode:指定编译代码的种类,可以指定为 ‘exec’,’eval’,’single’。当source中包含流程语句时,mode应指定为‘exec’; 当source中只包含一个简单的求值表达式,mode应指定为‘eval’;当source中包含了交互式命令语句,mode应指定为'single'。 5.当一个字符串被exec,eval(),或execfile()执行时,解释器会先将它们编译为字节代码,然后再执行.这个过程比较耗时, 所以如果需要对某段代码执行很多次时,最好还是对该代码先进行预编译,这样就不需要每次都编译一遍代码,可以有效提高程序的执行效率。'''#exec:当source中包含流程语句时,mode应指定为‘exec’code1 = "for i in range(10):print(i)"compile1 = compile(code1,'','exec')exec(compile1)#eval:当source中只包含一个简单的求值表达式,mode应指定为‘eval’code2 = "3 + 5 -6*7"compile2 = compile(code2,'','eval')print(eval(compile2))#single:当source中包含了交互式命令语句,mode应指定为'single'code3 = 'name = input()'compile3 = compile(code3,'','single')exec(compile3)print(name)
4.json和pickle数据序列化
json序列化:把内存中的数据和对象存到硬盘中(文件只能写进字符串)
注:json序列化只支持最简单的数据类型,像函数这种不能序列化
序列化:
import jsoninfo = { "name":"alex", "age":22,}f = open("test.txt","w",encoding="utf-8")f.write(json.dumps(info))f.close()'''def sayhi(name): print("hello,",name)info = { "name":"alex", "age":22, "func":sayhi}f = open("test2","w",encoding="utf-8")f.write(json.dumps(info)) #error,is not JSON serializablef.close()'''
#dump一次就load一次,不能多次load;每dump一次就生成一个新的文件,再load一次import jsoninfo = { "name":"alex", "age":22,}f = open("test.txt","w",encoding="utf-8")f.write(json.dumps(info))info["age"] = 20f.write(json.dumps(info))data = json.loads(f.read())#errorf.close()
反序列化:
import jsonf = open("test.txt","r",encoding="utf-8")data = json.loads(f.read())#data = json.load(f)print(data)f.close()
5.软件目录规范
软件结构规范:为什么要设计好目录结构 “设计目录结构”就和“代码编写风格”一样,属于个人风格问题。 设计一个层次清晰的目录结构,就是为了达到以下两点: 1.可读性高:不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等 从而快速的了解这个项目 2.可维护性高:定义好组织规则后,维护者就能很明确的知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是随着时间的推移, 代码/配置的规模增加,项目结构不会混乱,仍然能组织良好 因此保持一个层次清晰的目录结构是有必要的。更何况组织一个良好的工程目录,其实是一个很简单的事儿目录组织方式: 关于如何组织一个较好的python工程目录结构,已经有一些得到了共识的目录结构。在StackOverflow的这个问题上, 能看到大家对python目录结构的讨论。 假设你的项目名为foo,我比较建议的最方便快捷目录结构这样就足够了: Foo/ |-- bin/ | |-- foo | |-- foo/ | |-- test/ | | |-- _init_.py | | |-- test_main.py | | | |-- _init_.py | |-- main.py | |-- docs/ | |-- conf.py | |-- abc.rst | |-- setup.py |-- requirements.txt |-- README 简单解释一下: 1.bin/:存放项目的一些可执行文件,当然你可以起名script/之类的也行 2.foo/:存放项目的所有源代码。(1)源代码中的所有模块、包都应该放在此目录,不要置于顶层目录。 (2)其子目录tests/存放单元测试代码 (3)程序的入口最好命名为main.py 3.docs/:存放一些文档。 4.setup.py:安装、部署、打包的脚本。 5.requirements.txt:存放软件依赖的外部python包列表 6.README:项目说明文件,目的是能简单描述该项目的信息,让读者快速了解这个项目 它需要说明一下几个事项: 1.软件定位,软件的基本功能 2.运行代码的方法:安装环境、启动命令 3.简要的使用说明 4.代码目录结构说明,更详细点可以说明软件的基本原理。 5.常见问题说明