python第四周学习内容
Posted bupt-mrwu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python第四周学习内容相关的知识,希望对你有一定的参考价值。
1.装饰器
定义:本质是一个函数,(装饰其他函数)就是为其他函数添加附加功能
原则:不能修改被装饰函数的源代码,不能修改被装饰函数的调用方式
实现装饰器的知识储备:
函数即“变量”。每当定义一个函数时,函数的名字就是变量的名字,函数体就是变量的内容
‘‘‘ error def foo(): print("in the foo") bar() foo() ‘‘‘‘‘‘ OK def bar(): print("in the bar") def foo(): print("in the foo") bar() foo() ‘‘‘‘‘‘ OK def foo(): print("in the foo") bar() def bar(): print("in the bar") foo() ‘‘‘‘‘‘ error def 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 func bar = test2(bar) #==》@test2 bar()‘‘‘
嵌套函数:
嵌套函数+高阶函数=》装饰器
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=wrapper def test(): time.sleep(10) print("in the tset") test()
装饰器完整程序示例:
测试时间
import time def 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 time user_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 = wrapper def 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<max: yield n n += 1 count = counting(100) print(count.__next__()) print("My name is Mr Wu") print(count.__next__()) print("I am a man") print(count.__next__()) print("I am 19 years old") print(count.__next__()) print("I like Python") print(count.__next__()) print("I like C") for i in count: print(i)
迭代器:
可以被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 time def 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,否则返回False print(any([0,-4,5])) #如果Iterable内部有一个元素为真,返回True,否则(Iterable为空)返回False a = ascii([1,2,"开外挂"]) #把列表变成了一个字符串 print(type(a),[a]) #<class ‘str‘> ["[1, 2, ‘\u5f00\u5916\u6302‘]"] print(bin(1)) #将数字转换为二进制 print(bool(0)) #判断真假 True、False a = 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] = 50 print(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 functools res = 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 json info = { "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, <function sayhi at 0x0000012217F211E0> is not JSON serializable f.close() ‘‘‘
#dump一次就load一次,不能多次load;每dump一次就生成一个新的文件,再load一次 import json info = { "name":"alex", "age":22, } f = open("test.txt","w",encoding="utf-8") f.write(json.dumps(info)) info["age"] = 20 f.write(json.dumps(info)) data = json.loads(f.read())#error f.close()
反序列化:
import json f = 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.常见问题说明
以上是关于python第四周学习内容的主要内容,如果未能解决你的问题,请参考以下文章