一、装饰器
装饰器::: 本质 是函数,功能是为了装饰其它函数。就是为其他函数添加附加功能 原则 1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式实现装饰器知识储备:1.函数即“变量” 变量存在在内存当中,变量的回收机制,当没有引用的时候,就回收变量2.高阶函数 a、把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能) b、返回值中包含函数(不修改函数的调用方式) 3.嵌套函数 函数进行嵌套高阶函数+嵌套函数=》装饰器
def logger(): print("log is here!") def test1(): pass logger() def test2(): pass logger() test1() test2() ‘‘‘ def timmer(func): def warpper(*args,**kwargs): start_time = time.time() func() stop_time = time.time() print("The func run time is %s" %(stop_time-start_time)) return warpper @timmer def test1(): time.sleep(3) print("In the test1") test1()
‘‘‘decorator 装饰器 语法糖 高级装饰器: 网站--页面(一个网站一个函数)100个页面不需要登录 现20个需要登录才能访问 ‘‘‘ user,passwd = "alex","abc_123" def auth1(func): def wrapper(*args,**kwargs): username = input("Username").strip() password = input("Password").strip() if user == username and passwd == password: print("welcome!") return func(*args,**kwargs) return wrapper def index(): #不需要登录 print("welcome to index page") @auth1 def home(): #需要登录 print("welcome to home page") home()
二、生成器
‘‘‘列表生成器‘‘‘ a = [1,2,3,4] #列表生成式 b = [i*2 for i in range(10)] c = [] for i in range(10): c.append(i*2) print(a,b,c) ‘‘‘生成器 generator g = (i**2 for i in range(10)) 1、只有在调用时才会生成相应的数据 。 2、只记住当前位置 3、只有一个3.0 __next__()【2.7 next()】方法 如果全部展示 只能用for 循环全部调用 可以使用函数生成 主要是 yield 关键字 把什么返回到外面,就把yeild关键字放到那边 yeild返回函数当前的值 ‘‘‘ def fib(max): n,a,b =0,0,1 while n<max: #print(b) yield b a,b =b,a+b n=n+1 return("done") f = fib(10) # for j in fibg: # print(fibg.__next__()) while True: try: print(f.__next__()) except StopIteration as e: print("Generator return value:" ,e.value) break
#! /usr/bin/env python # -*- coding:utf-8 -*- # Auther:Xll ‘‘‘协程‘‘‘ import time def consumer(name): print("%s 准备吃包子了!" %name) while True: baozi = yield print("包子【%s】个来了,被【%s】吃了!" %(baozi,name)) # c = consumer("Chenronghua") # c.__next__() # c.send("白菜大葱") def producter(name): c = consumer("Alex") c1 = consumer("Wutengnan") c.__next__() c1.__next__() print("%s宣布:吃包子大赛开始!" %name) for i in range(10): time.sleep(i) print("做了%s个包子" %((i+1)*2)) c.send(i+1) c1.send(i+1) producter("Oldboy")
三、迭代器
可以用于 for 循环的对象,叫可迭代对象Iterable 可以被next 函数调用并不断返回下一个值得对象称为 迭代器 dir() 查看这个数据的所有方法 from collections import Iterator Iterable isstance([],Iterable) 迭代器标示的是一个数据流生成器 是可迭代对象,通过Iter()方法可以把 列表、字典,字符串 变成迭代器
四、常用内置模块
#! /usr/bin/env python # -*- coding:utf-8 -*- # Auther:Xll ‘‘‘内置方法‘‘‘ #all 内部元素所有为真,返回真 print(all([111,1,2,3,-1])) #any 内部任意元素为真,返回真 print(any([0,1,False])) #内部数据转为可打印的字符串形式,中文转为unicode格式 s=[1,2,3,45,6,7,8,90,67] s.append(‘开外挂‘) print(ascii(s)) #bin 整数 10进制转2进制 print(bin(64)) #bool() 判断真假 0 空列表,空字典为假,其他为真 print(bool(False)) #转换位bit格式 a = bytes("abcde",encoding="utf-8") print(a.capitalize(),a) #bytearray 变为可列表,可操作列表来实现改变,但数据类型是bytearray b = bytearray("abcde",encoding="utf-8") print(b[2]) #98 b[1]=80 print(b,type(b)) #callable 是否可调用, 函数、类是可调用的,即可以加()的 print(callable(s)) #char 用数字转换为ascii码的字符,ord 相反 print(chr(97)) print(ord("b")) #classmethod 类方法 #print(chr(97)) #complie 变成可执行的代码 的过程 #divmod A/B 返回 商 和 余数 print(divmod(100,33)) #eval 把一个字符串变字典。 #exce 把一个字符变为可执行程序 #匿名函数 lambda 只能写三元运算,不能做更多的判断 calc = lambda n:print(n) calc1 = lambda n:3 if n<4 else n calc(5) print(calc1(1)) #filter 一组数据中过滤出你想要的,配合lambda使用 res = filter(lambda n:n>5,range(10)) for i in res: print(i) #map 对传入的值按照函数的方式处理,然后返回 ret = map(lambda n:n**2,range(10)) for j in ret: print(j) #frozenset 不可变集合 aa = frozenset([11,22,33,44,33,22,11,55,66]) print(aa) #globals 返回当前文件中所有变量的k v 格式 print(globals()) #hash print(hash(aa)) #hex 数字转16进制 oct 数字转8进制 a = {0: 10000, 6: 2, 1: 4, -5: 6, 99: 11, 1111: 32} print(sorted(a.items())) #按照key排序 print(sorted(a.items(),key = lambda x:x[1])) #按照value排序 #zip 拉链函数 ,以最短的聚合 a=[1,2,3,4] b=[‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘] for i in zip(a,b): print(i) (1, ‘a‘) (2, ‘b‘) (3, ‘c‘) (4, ‘d‘) __import__(‘decorator‘)
json和pickle
info ={‘name‘:‘alex‘,‘age‘:22} # with open(‘test.txt‘,"w") as f: # f.write(str(info)) # with open(‘test.txt‘,"r") as f: # data=eval(f.read()) # print(data) ‘‘‘json 序列化和反序列化 json.dumps() json.loads() ‘‘‘ import json # with open(‘test.txt‘,"w") as f: # f.write(json.dumps(info)) # with open(‘test.txt‘,"r") as f: # data = json.loads(f.read()) # print(data,type(data)) ‘‘‘pickle 只能在python中使用,可以对所有数据类型按照bit格式 进行写入和读取操作‘‘‘ import pickle def sayhi(name): print("Hello",name) info[‘func‘] = sayhi # print(info) # print(pickle.dumps(info)) # with open(‘test.txt‘,"wb") as f: # f.write(pickle.dumps(info)) with open(‘test.txt‘,"rb") as f: data = pickle.loads(f.read()) print(data["func"](‘alex‘))
import的本质:
‘‘ 包:本质就是一个文件夹,区别是必须带有__init__.py文件 导入包的本质是解释包下面的__init__.py文件 模块: 1、定义:模块用来从逻辑上组织python代码(变量、函数、类,逻辑:实现一个功能) 本质上就是以.py结尾的python文件(文件名test.py对应的模块名:test) 2、导入方法 import module_1 import module_1,module_2 from module_1 import * (不使用,容易出现变量等冲突) from module_1 import m1,m2,m3 from module_1 import logger as logger_m 3、import本质(路径搜索和搜索路径) 把文件解释一遍,import 文件名代表导入所有,from只解释from的那一段, import module_name ----->module_name.py---->必须找到文件的路径 在sys.path 列出的路径下找 4、导入优化 多次调用 import module 中的test方法时,会造成效率低下, 建议使用 from module import test 或者加上 as module_test_test 5、模块的分类: a:标准库 b:开源模块 c:自定义模块 ‘‘‘ #import module_1 = module_1 = all code #from module_1 import say_hi 把module_1中的say_hi 函数放到当前位置,并命名为 say_hi import module_1 module_1.say_hi() from module_1 import say_hi name1 = "Wu Teng Nuan" say_hi() #导入包 import package_test
os模块
import os print(os.getcwd()) #获取当前工作目录,即当前python脚本工作的目录路径 print(os.chdir("c:\\")) # 改变当前脚本工作目录;相当于shell下cd os.curdir #返回当前目录: (‘.‘) os.pardir #获取当前目录的父目录字符串名:(‘..‘) os.makedirs(‘dirname1/dirname2‘) # 可生成多层递归目录 os.removedirs(‘dirname1‘) # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir(‘dirname‘) # 生成单级目录;相当于shell中mkdir dirname os.rmdir(‘dirname‘) # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir(‘dirname‘) # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() # 删除一个文件 os.rename("oldname","newname") #重命名文件/目录 os.stat(‘path/filename‘) # 获取文件/目录信息 os.sep # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep # 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep # 输出用于分割文件路径的字符串 os.name # 输出字符串指示当前使用平台。win->‘nt‘; Linux->‘posix‘ os.system("bash command") # 运行shell命令,直接显示 os.environ #获取系统环境变量 os.path.abspath(path) # 返回path规范化的绝对路径 os.path.split(path) # 将path分割成目录和文件名二元组返回 os.path.dirname(path) # 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) # 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) #如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) #如果path是绝对路径,返回True os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) #如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) # 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) #返回path所指向的文件或者目录的最后修改时间
shutil模块
##高级的 文件、文件夹、压缩包 处理模块 import shutil #shutil.copyfileobj(‘os-mk.py‘, ‘os-1‘,100) #将文件内容拷贝到另一个文件中,可以部分内容 shutil.copyfile("os-mk.py","os-mk") #拷贝文件 shutil.copymode("os-mk.py","os-mk") #仅拷贝权限。内容、组、用户均不变 !!! linux 比较适用,windows下看不出来太大区别 shutil.copystat("os-mk.py","os-mk") #拷贝状态的信息,包括:mode bits, atime, mtime, flags shutil.copy("os-mk.py", "os-mk1") #拷贝文件和权限 shutil.copy2("os-mk1","os-m1") #拷贝文件和状态信息 #shutil.ignore_patterns(*patterns) #shutil.copytree(src, dst, symlinks=False, ignore=None) #递归的去拷贝文件,文件夹 #shutil.copytree(‘py06‘, ‘py05‘, ignore=shutil.ignore_patterns(‘*.pyc‘, ‘tmp*‘)) #shutil.rmtree(‘py05‘) #递归的去删除文件 #shutil.move(‘py06‘, ‘py04‘) #递归的去移动文件 ‘‘‘ shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, 如:www =>保存至当前路径 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/ format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar” root_dir: 要压缩的文件夹路径(默认当前目录) owner: 用户,默认当前用户 group: 组,默认当前组 logger: 用于记录日志,通常是logging.Logger对象 ‘‘‘ shutil.make_archive(‘aaaa.tar‘, ‘tar‘)
shelve模块
是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式
import shelve d = shelve.open(‘shelve--test‘) # 打开一个文件 # d["name"] = ["alex", "WutN", "test"] # d["age"] = 22 # 持久化类 # d[‘info‘] = {"name":"alex","age":21,"school":"Oldboy"} # d.close() print(dir(d)) print(d.get("name")) print(d.get("info"))
logging模块
很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()
, info()
, warning()
, error()
and critical() 5个级别,
下面我们看一下怎么用。
最简单用法
import logging logging.warning("user [alex] attempted wrong password more than 3 times") logging.critical("server is down") #输出 WARNING:root:user [alex] attempted wrong password more than 3 times CRITICAL:root:server is down
看一下这几个日志级别分别代表什么意思
Level | When it’s used |
---|---|
DEBUG |
Detailed information, typically of interest only when diagnosing problems. |
INFO |
Confirmation that things are working as expected. |
WARNING |
An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR |
Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL |
A serious error, indicating that the program itself may be unable to continue running. |
如果想把日志写到文件里,也很简单
1 2 3 4 5 6 |
|
其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
1 |
|
感觉上面的日志格式忘记加上时间啦,日志不知道时间怎么行呢,下面就来加上!
1 2 3 4 5 6 |
|
日志格式
%(name)s |
Logger的名字 |
%(levelno)s |
数字形式的日志级别 |
%(levelname)s |
文本形式的日志级别 |
%(pathname)s |
调用日志输出函数的模块的完整路径名,可能没有 |
%(filename)s |
调用日志输出函数的模块的文件名 |
%(module)s |
调用日志输出函数的模块名 |
%(funcName)s |
调用日志输出函数的函数名 |
%(lineno)d |
调用日志输出函数的语句所在的代码行 |
%(created)f |
当前时间,用UNIX标准的表示时间的浮 点数表示 |
%(relativeCreated)d |
输出日志信息时的,自Logger创建以 来的毫秒数 |
%(asctime)s |
字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
%(thread)d |
线程ID。可能没有 |
%(threadName)s |
线程名。可能没有 |
%(process)d |
进程ID。可能没有 |
%(message)s |
用户输出的消息 |
如果想同时把log打印在屏幕和文件日志里,就需要了解一点复杂的知识 了
Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:
logger提供了应用程序可以直接使用的接口;
handler将(logger创建的)日志记录发送到合适的目的输出;
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。
logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr
2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a‘,即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
re模块:::
常用正则表达式符号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
最常用的匹配语法
1 2 3 4 5 |
|
反斜杠的困扰
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
仅需轻轻知道的几个匹配模式
1 2 3 |
|
import re #re.match 匹配是否以字符开始 没有匹配上返回None,此时不具有group属性,会报错。 #re.serch 全文搜索 #re.findall 搜索所有的 #re.split 以匹配到的进行分割 #re.sub() 以第二个来替换匹配到的信息 re.sub(search,repl,string,count=) a = re.match("\w*",‘inter 192.168.0.161‘) print(a,a.group()) # group 和groups的却别, groups 打印出分组()中匹配到的数据 b = re.match(‘(\d{2})(\d{2})(\d{2})(\d{4})‘,‘212312200212172233 name:alex‘) print(b.group()) print(b.groups()) print(re.search(‘^\d.*\d\Z‘,‘213123124xyz1432432‘).group()) # ?P<内容> 搭配groupdict(),转为字典格式,装逼ing cc = re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<year>[0-9]{4})","212312200212172233") print(cc.groups()) print(cc.group()) print(cc.groupdict()) print(re.findall(‘\w‘,‘[email protected]@ww$$$$‘)) print(re.split(‘\d+‘,‘ads1ljkk132kjh43h234jhj24k3hj234jkh66‘)) print(re.sub(‘\d+‘,‘||‘,‘ads1ljkk132kjh43h234jhj24k3hj234jkh66‘)) # 自然语言,不对字符串进行转移 logs‘string‘ print(re.split(‘\\\\‘,logs‘c:\\user\pwd\new\python33‘)) print(re.split(logs‘\\‘,logs‘c:\\user\pwd\new\python33‘)) #flags re.I 忽略大小写 re.M 多行模式 re. print(re.search(‘a‘,‘ABC‘,flags=re.I)) print(re.search(‘^A.*\w$‘,‘ABCabcdsfs4\n213789sdff‘, flags=re.M).group())
#re.match 匹配是否以字符开始 没有匹配上返回None,此时不具有group属性,会报错。#re.serch 全文搜索#re.findall 搜索所有的#re.split 以匹配到的进行分割#re.sub() 以第二个来替换匹配到的信息 re.sub(search,repl,string,count=)a = re.match("\w*",‘inter 192.168.0.161‘)print(a,a.group())# group 和groups的却别, groups 打印出分组()中匹配到的数据b = re.match(‘(\d{2})(\d{2})(\d{2})(\d{4})‘,‘212312200212172233 name:alex‘)print(b.group())print(b.groups()) print(re.search(‘^\d.*\d\Z‘,‘213123124xyz1432432‘).group())# ?P<内容> 搭配groupdict(),转为字典格式,装逼ingcc = re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<year>[0-9]{4})","212312200212172233")print(cc.groups())print(cc.group())print(cc.groupdict()) print(re.findall(‘\w‘,‘[email protected]@ww$$$$‘)) print(re.split(‘\d+‘,‘ads1ljkk132kjh43h234jhj24k3hj234jkh66‘))print(re.sub(‘\d+‘,‘||‘,‘ads1ljkk132kjh43h234jhj24k3hj234jkh66‘))# 自然语言,不对字符串进行转移 logs‘string‘print(re.split(‘\\\\‘,logs‘c:\\user\pwd\new\python33‘))print(re.split(logs‘\\‘,logs‘c:\\user\pwd\new\python33‘))#flags re.I 忽略大小写 re.M 多行模式 re.print(re.search(‘a‘,‘ABC‘,flags=re.I))print(re.search(‘^A.*\w$‘,‘ABCabcdsfs4\n213789sdff‘, flags=re.M).group()) print(re.search(‘.+‘,‘ABC\n2137\n89sdff‘, flags=re.S).group())