装饰器
器:表示的是函数 装饰器本质上是函数
装饰器是为了装饰其他函数。就是为其他功能添加附加功能。
装饰器的原则是:1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
实现装饰器需要明白:
1、函数即“变量” :函数与变量一样都是存在内存中的,若索引不被删除,则一直在内存中驻留到程序结束。
2、高阶函数
1)把一个函数名当做实参传给另外一个函数,在不修改被装饰函数源代码的情况下为其添加功能。
2)返回值中包含函数名(不修改函数的调用方式)
3、嵌套函数
最终:高阶函数+嵌套函数=装饰器
最简单的装饰器如下所示:
部分网站页面在制作完成以后,可能需要经过认证才可以进行下一步的访问,具体实现:
# -*- coding:utf-8 -*- def login(func): def user_pass(): user=input("请输入用户名:") password=input("请输入密码:") if user=="miss" and password=="miss": res=func() return res#结束处需要记得返回当前func运行的结果,否则会将存在return的函数的结果丢失 else: print("输入错误,请重试") return user_pass @login#装饰器语法 def index(): print("welcome to index") return"from home" @login def bbs(): print("welcome to bbs") def email(): print("welcome to email")
bbs()
日常的装饰器使用就如展示所示,将login函数冠在要装饰的函数之上,即可完成给函数增加新功能,同时,被装饰函数既感觉不到装饰器的存在,也不会因为被装饰而改变了调用方式。
上面这种是无需往装饰器中传参数的,而另外一种则可能需要往装饰器中传参,比如实现不同页面不同认证方式的效果。
那么我们就可以进行如下所示操作:
# -*- coding:utf-8 -*- def login(auth_type):#先行传入认证类型 def outer_wapper(func): def user_pass(): user=input("请输入用户名:") password=input("请输入密码:") if auth_type=="local": if user=="miss" and password=="miss": res=func() return res#结束处需要记得返回当前func运行的结果,否则会将存在return的函数的结果丢失 else: print("输入错误,请重试") elif auth_type=="ldap": print("暂无此种认证") return user_pass return outer_wapper @login(auth_type="ldap")#加入auth_type以后,整体的传入参数往下压一级 def index(): print("welcome to index") return"from home" @login(auth_type="local") def bbs(): print("welcome to bbs") def email(): print("welcome to email") index() bbs()
这种方式使用较为普遍。
还有一种方式,是在做作业的时候用到的,就是被装饰函数需要从装饰器中获取自己需要的值,比如还是登录的情况,如果用户登录成功, 那么后续函数会生成一个以当前用户名为文件名的文件,来记录相关信息。而用户登录是在装饰器中完成的,若装饰器无法返回相关相关数据,后续函数则无法完成对应的工作,那么就可以使用如下方式进行提取数据:
# -*- coding:utf-8 -*- def denglu(func): def renzheng(msg): user=input("用户名:") passwd=input("密码:") if user=="admin" and passwd=="123": print("认证成功!") msg.append(user) #认证成功后,将用户名和密码追加到列表中,通过在return中完成对msg的返回。 msg.append(passwd) return func(msg) return renzheng @denglu def Main(msg): #函数在收到msg之后,首先对msg进行分离,按照添加的顺序,一一拆分出来。 user=msg[0] passwd=msg[1] print("登录成功的用户是%s,密码是%s,创建文件名为%s的文件"%(user,passwd,user)) if __name__ == '__main__': msg=[] #此处首先创建一个空列表,方便后续对登录用户名和密码的收集 Main(msg)
从上面的例子可以看出,我们用了一个列表,按照既定规则追加拆分,即可得到想要得到的数据。此类方法不局限于使用列表,也可以使用字典的形式,如:
msg={} msg.update("user":user) msg.update("passwd":passwd)
生成器
在Python中,一边循环一边计算的机制,成为生成器 generator
1、只有在调用时才会生成相应的数据
2、只记录当前位置
3、只有一个_next_()方法 在Python2.7里面为next()
可以使用如下代码进行生成器的测试。
import time a=time.time() s=[i*2 for i in range(0,10000)] b=time.time() print(b-a) #0.0010023117065429688
import time a=time.time() s=(i*2 for i in range(0,100000000)) b=time.time() print(b-a) #0.0
后者其实并未生成真是的数据,因此速度较快。
由生成器可得生成器函数模型:
# -*- coding:utf-8 -*- def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n+=1 return "done" print(fib(10))
yield 可以实现单线程的情况下并发运算的效果。
yield的效果是保留当前结果并暂停
next只是调用yield 不会给yield传值
send是调用yield,同事给yield传值
生产者消费者模型:
# -*- coding:utf-8 -*- import time def consumer(name): print("%s准备开始吃包子啦"%name) while True: baozi=yield print("包子%s来了,被%s吃掉了"%(baozi,name)) def producer(name): c1=consumer("gao") c2=consumer("yang") c1.__next__() #相当于让consumer成为生成器,启用next之后,就让consumer走到了yield这一步,随后停止 c2.__next__() print("%s开始制作包子"%name) for i in range(3): time.sleep(1) print("做一个包子") c1.send(i) c2.send(i) producer("li")
迭代器
可以直接作用于for循环的数据类型:
1、集合数据类型: 如 列表list、元组tuple 、 字典dict、 集合set、 字符串str、 字节类型byte等
2、generator 包括生成器和带yield的generator function
可迭代 即为可循环
可以使用isinstance()判断是否为迭代器对象
可以被for循环的对象叫做可迭代对象 iterable可迭代
可以被netxt()函数调用并不断返回下一个值的对象成为可迭代器:iterator。
凡是可作用于for循环的对象都是iterable类型
凡是可作用于next()函数的对象都是iterator类型,他们表示一个惰性计算的序列
集合数据类型如list dict str 等是iterable 但不是iterator,不过可以通过iter()函数获得一个iterator对象
Python中的for循环本质上就是通过不断调用next()函数实现的
JSON AND PICKEL
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。json所有语言都通用,可以与不同语言进行数据交互,json默认只是支持最简单的转换类型。与XML相同,但比XML更为简洁方便。
# -*- coding:utf-8 -*- import json a={ 1:"2", 2:"3", 4:"5" } with open("json.txt","w") as f: f.write(json.dumps(a)) #########序列化 with open("json.txt","r") as f: data=json.loads(f.read())##########反序列化 print(data["1"])
res: 2
pickel
用法跟json类似,但是可以用于python特有的类型 和 python的数据类型间进行转换。
# -*- coding:utf-8 -*- import pickle a={ 1:"2", 2:"3", 4:"5" } with open("pickle.txt","wb") as f: f.write(pickle.dumps(a)) with open("pickle.txt","rb") as f: data=pickle.loads(f.read()) print(data[1])
内置模块
1、定义:
模块:用来从逻辑上组织python代码(变量、函数、类、逻辑,从而实现一个功能),本质上就是一个.py结尾的python文件(如文件名为test.py, 则对应的模块名为:test)
python包:本质就是一个文件夹(必须带有一个_init_.py的文件)
2.导入方法:
1、 import module_name
2、import module_name,module2_name
3、from module_alex import * 从module_alex 中引用全部的内容,即相当于将module_alex中的内容复制出来了一份
4、frommodule_alex import 相关函数 可以使用此方式引入想用的函数或者是功能,这样引入的功能直接调用就可以,无需使用原文件名点出来
5、from module_alex import logger as logger_alex 将logger从module_alex中引入,并将其另外命名为logger_alex
3、导入模块的本质(路径搜索和搜索路径)
导入模块的本质就是把python文件解释一遍
导入包的本质就是执行包下面的_init_.py的文件
因此可以使用from .import test来进行函数的引用
如果要给一个py文件导入模块,那么一定要在sys.path中体现出来,即需要在系统默认的os.path中添加上
os.append()将当前目录追加进去
若想要提高此文件的优先级,可以使用os.insert()来将需要添加的放到前面。
4、导入模块的优化,如果一个模块经常性的使用,则可以使用from module import test 将其直接引入,这样可以避免每次都进行查找。
5、 模块的分类:
a.标准库
时间模块:time 和 datetime
获取时间戳 time.time()
用来表示时间的方式:1时间戳
2格式化的时间字符串
3元组(struct_time)
时间的分类:UTC 格林尼治天文时间,世界标准时间,中国使用的是UTC+8
DST 夏令时
time.timezone()显示当前所在时区
time.altzone()显示夏令时与当前时区的差值
time.daylight()是否使用了夏令时
time.sleep()时间停止多长时间,默认时间单位为秒
time.gmtime()当前时间的格林尼治时间 为UTC时区时间
time.localtime()当前时间
以上两种是把时间戳转换为元组的方法
由元组传转换为时间戳:mktime()
由元组转换为字符串:strtime("格式“,元组的时间)
由字符串转化为元组:striptime(”格式化的字符串“,格式)
time.ctime()由时间戳转换为字符串格式 时间戳
time.asctime()由元组转化为字符串格式 参数是元组 tuple
datetime.datetime.now()+datetime..timedelta(3) 当前时间的后三天
datetime.datetime.now()+datetime..timedelta(-3) 当前时间的前三天
random模块
random.random()默认随机0到1之间的数值,值类型为浮点数
random.uniform(1,10) 从一个范围内取值,值类型为浮点数
random.randint(1,3)随机1-3之间的整数,可以取到3的值
random.randrange(0,3) 随机1-3之间的整数,不能取到3的值
random.choice(“”)可以传入字符串、列表、元组等,从中取一个值;随机字符功能
random.sample(“ hello”,2)从前面的hello中取两个值;随机字符功能,指定取值几
OS模块
os.getcwd()获取当前的工作目录
os.chdir(r“c:\”)切换目录
os.curdir()返回当前目录 类似 Linux下的cd .
os.pardir()获取当前目录的父目录字符串 类似Linux下的cd ..
os.makedirs()递归创建目录
os.removedirs()若目录为空,则删除并递归到上一层,如若也为空,则删除,以此类推
os.mkdir("dirname") 创建目录 类似Linux下的mkdir test
os.rmdir() 删除目录,类似linux下的rm -rf
os.listdir()列出当前目录的文件列表
os.stat(“test”)获取test的文件信息
os.sep输出当前平台使用的路径分隔符
os.linesep输出当前平台使用的行终止符 windows下为“\r\n" Linux下为”\n"
os.environ列出当前系统的环境变量
os.pathsep输出用于分割文件路径的字符串
os.name 获取当前使用平台
os.system("dir")运行shell命令
os.path.abspath()获取某一文件的绝对路径
os.path.split(r"c:\d\e\f")将路径分割成目录和文件名二元组并返回
os.path.dirname(路径)取此path的路径的值
os.path.basename(路径) 取此path的文件名的值
(split、dirname、basename都可以不考虑后面的路径是否存在,其仅仅是处理字符串)
os.path.exists(r“c:\a”)返回此路径是否存在,存在为True,不存在为False
os.path.isabbs(路径)判断此路径是否为绝对路径 是为真 否为假
os.path.join()组合多个路径并返回值,第一个绝对路径之前的参数将被忽略
os.path.getatime() 返回路径所指向的文件或目录最后的存取时间
os.path.getmtime()返回路径所指向的文件或目录最后的修改时间
sys模块
sys.argv()命令行参数list,第一个元素是程序本身路径
sys.exit()退出程序,正常退出时exit(0)
sys.version()获取python解释程序的版本信息
sys.maxint()最大的int值
sys.path()返回模块的搜索路径,初始化时使用Pythonpath环境变量的值
sys.platform()返回操作系统平台名称
shutil模块(copy文件)
shutil.copyfile(sourceFile,destFile)从源文件拷贝到目标文件
shutil.copymode(sourceFile,destFile)仅拷贝权限,内容、组、用户均不变
shutil.copystat(sourceFile,destFile)拷贝状态的信息,不涉及文件内容
shutil.copy(sourceFile,destFile)拷贝文件和权限
shutil.cpoy2(sourceFile,destFile)拷贝文件和状态信息
shutil.copytree(sourceFile,destFile)递归的拷贝文件,即为拷贝文件夹
shutil.rmtree(sourceFile,destFile)递归的去删除文件,即为删除文件夹
shutil.make_archive(压缩包的名称,压缩类型,要压缩的路径,用户(默认当前用户),组(默认当前组),记录日志)
如shutil.make_archive(“test","zip",root_dir="c:\test\"
zipfile模块
#压缩
z=zipfile.ZipFile("test.zip","w")将要压缩的文件保存到test.zip中
z.write()
z.close()
#解压
z=zipfile.ZipFile(“test.zip‘,”r“)解压test.zip中的文件
z.extractall()#可设置解压路径,将压缩包内的文件全部解压
z.close()
tarfile模块
#压缩
tar=tarfile.open("test.zip","w")
tar.add()
tar.close()
#解压
tar=tarfile.open("test.zip","r")
tar.extractall()
tar.close()
json模块
json用于字符串和python数据类型间进行交换,可以做到不同语言之间的数据传输
只支持简单的数据类型
pickle模块
用于python特有的类型和Python的数据类型间进行转换
shelve模块
shelve模块是一个简单的将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的Python数据格式
例:
import shelve
d=shelve.open("test.txt")#打开一个文件
name=[“rain”,“ass”。“dss”]
num=[1,2,3,4,5]
d["name"]=name
d["num"]=num
d.close()
xml处理模块
#创建xml文件 import xml.etree.cElementTree as et new_xml=et.Element("namelist") name=et.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = et.SubElement(name,"age",attrib={"checked":"no"}) sex = et.SubElement(name,"age") sex.text = '20' name2 = et.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = et.SubElement(name2,"age") age.text = '19' et = et.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True
#修改xml文件 import xml.etree.ElementTree as et tree = et.parse("xmltest.xml") root = tree.getroot() #修改 for node in root.iter('year'): new_year = int(node.text) + 1 node.text = str(new_year) node.set("updated","yes") tree.write("xmltest.xml")
#删除node for country in root.findall('country'): rank = int(country.find('rank').text) if rank > 50: root.remove(country) tree.write('output.xml')
hashlib模块
用于执行加密的相关操作,3.x中代替了md5模块和sha模块,主要是提供SHA1、SHA224、SHA256、SHA256、SHA384、SHA51、MD5算法
用法:
import hashlib s=hashlib.md5() s.update(b"hello") print(s.hexdigest())#加密后以十六进制显示 print(s.digest())#加密后以二进制显示
hmac模块:可以创建key和内容,处理以后再进行加密
hmac 散列消息鉴别码,是一种基于消息鉴别码的鉴别机制,使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;一般用于网络通信中消息加密,前提是两者都知道K的值
用法:
import hmac
s=hmac.new(b"youloveit","你好,我是mir赵".encode(encoding="utf-8"))
print(s.hexdigest())
logging模块
用于存储各类格式的日志,有5个告警级别:debug(),info(),warning(),error(),critical()
屏幕输出
屏幕输出 import logging logging.debug("this is a debug") logging.info("this is a info") logging.warning("this is a warning")#默认从此处开始在屏幕上显示 logging.error("this is a error")
写入文件
写入文件:(不会在屏幕输出) import logging logging.basicConfig(filename="filename.txt",level=logging.DEBUG) logging.debug("this is a debug") logging.info("this is a info") logging.warning("this is a warning") logging.error("this is a error")
OR
import logging logging.basicConfig(filename="filename.txt",level=logging.DEBUG,format=("%(asctime)s %(message)s"),datefmt="%Y-%m-%d %H:%M:%S") logging.debug("this is a debug") logging.info("this is a info") logging.warning("this is a warning") logging.error("this is a error") #此处的basicconfig表示的是保存到文件名为filename.txt的文件中,保存等级是从debug开始,格式是“时间 信息” 日期格式为年-月-日 时-分-秒
将日志既要屏幕输出还要存入文件:
#logger提供一个能用程序可以直接时候用的接口 #handle将日志记录发送到合适的目的输出(一个handle就是一个输出地) #filter提供了细度设备来输出哪条日志记录 #formatter决定日志记录的最终输出格式 #每个程序在输出信息之前都要获得一个logger,即需要为其取一个名称: import logging #定义一个logger Log=logging.getLogger("chat.ui") Log.setLevel(logging.WARNING)#设置默认级别为warning #设置格式时间-告警logger名称-告警级别-日志信息 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #设置两个handle 一个指向屏幕,一个指向文件 screen=logging.StreamHandler() #屏幕默认级别为错误 screen.setLevel(logging.CRITICAL) screen.setFormatter(formatter) #文件默认级别为debug fileimput=logging.FileHandler("fileinput.txt",mode="a",encoding="utf-8") fileimput.setLevel(logging.DEBUG) fileimput.setFormatter(formatter) Log.addHandler(screen) Log.addHandler(fileimput) Log.debug('this is a debug message') Log.info('this is a info message') Log.warn('this is a warn message') Log.error('this is a error message') Log.critical('this is a critical message')
按照时间自动截断文件备份
import logging from logging import handlers #设置logger,定义告警级别,设置格式 Log=logging.getLogger("chat.core") Log.setLevel(logging.DEBUG) formatter =logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #屏幕输出 screen =logging.StreamHandler() screen.setLevel(logging.INFO) screen.setFormatter(formatter) #文件输出 #文件名为filetime 时间是按照秒计算,备份数量最多两份,编码类型为utf-8 fileinput =handlers.TimedRotatingFileHandler \ ("filetime",when="S",backupCount=2,encoding="utf-8") fileinput.setLevel(logging.INFO) fileinput.setFormatter(formatter) #将文件输出和屏幕输出添加到Log中,完成接口挂靠 Log.addHandler(screen) Log.addHandler(fileinput) #内容 Log.debug('this is a debug message') Log.info('this is a info message') Log.warn('this is a warn message') Log.error('this is a error message') Log.critical('this is a critical message')