2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 小白IT:python的函数内置方法常用的模块详解-方法-使用-坚持就是胜利

小白IT:python的函数内置方法常用的模块详解-方法-使用-坚持就是胜利

时间:2023-03-06 16:17:40

相关推荐

小白IT:python的函数内置方法常用的模块详解-方法-使用-坚持就是胜利

文章目录

Python 匿名函数&内置函数&常用模块一 内置函数1.作用域相关2.其他:3 输出相关4 数据类型相关5 内存相关6 文件操作相关7 模块操作相关8 调用相关9 数字相关10 数据结构相关11 数据集合12 sorted方法 二 匿名函数**map(func, iter)**filter(func, iter): 过滤函数reduce(func, iter)三 模块1 collections**模块2 namedtuple 命名元组3 deque 双端队列4 defaultdict 默认字典5 Counter** 计数6.time**模块python中的时间time模块的常用方法 7 datetime模块8 date模块9 dateutil模块10 random模块**:练习: 11 os模块**常用方法1.文件相关2.文件相关3.环境相关4.路径相关(重要) 12 sys模块 **常用方法sys.argv方法sys.exit(n)sys.stdout() 13.序列化模块****json模块**Json 源码**json注意点:**pickle模块shelve模块 14 logging 日志模块**函数式简单配置logger对象配置**logging模块的四大天王****Logger与Handler的级别****Logger的继承(了解)****应用**logging配置使用关于如何拿到logger对象详细解释 15 configparser模块**配置文件样式如下****读取操作****写入操作**练习 16.hashlib模块**加盐加密模拟撞库破解密码 17 hmac 模块18 suprocess模块 四 包

Python 匿名函数&内置函数&常用模块

我们之前学过函数的知识,知道函数的调用方式:

函数名()

然后函数在调用之前需要定义,定以后我们就可以使用了,但是有没有发现有些很特别呢?

比如说print(),我们用的很频繁的一个函数,打印内容,我们再使用这个函数的时候,好像我们也没有定义这个函数啊,为什么就能直接拿来用了呢?

诸如此类的函数还有很多,如len()、input()等等

其实这些函数就是python中的内置函数

python环境中已经为我们定义好的一些完成特定功能的函数,在python环境的任何地方我们可以直接调用。

一 内置函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7eOwHXK-1588872144752)(/Users/xujiazeng/Library/Application Support/typora-user-images/image-012116728.png)]

上面就是内置函数的表格(目前),68个内置函数,下面我们按照功能的类别归类成以下6大类,依次来学习。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eL57Mm1s-1588872144755)(/Users/xujiazeng/Library/Application Support/typora-user-images/image-012134584.png)]

1.作用域相关

基于字典的方式获取局部变量和全局变量

globals(): 全局变量的字典

locals(): 获取执行本方法所在命名空间内的局部变量的字典

locals(): 打印局部变量,以字典形式返回,可以使用get方法

vars(): 如果没有参数,和locals()一样,返回本地变量名和值,放在字典中,如果有参数,则是查看某一个对象的所有方法,放在字典里面。

2.其他:

字符串类型代码的执行

eval():将字符串类型的代码去掉引号并执行,不推荐使用

##将字符串转成相应的对象(如list、tuple、dict和string之间的转换),打开字符串a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"b = eval(a)print(b)#[[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]a = "{1:'xx',2:'yy'}"c = eval(a)print(c)#{1: 'xx', 2: 'yy'}a = "(1,2,3,4)"d = eval(a)print(d)#(1, 2, 3, 4)##将字符串str当成有效的表达式来求值并返回计算结果。所以,结合math当成一个计算器很好用print(eval('2''*''3')) # 加减乘除6

exec():将字符串类型的代码去掉引号后并执行,eval升级版,不推荐使用

code = '''import os print(os.path.abspath('.'))'''code = '''print(123)a = "20"print(a)'''a = 10exec(code)print(code)123 # exec 执行字符串中print 输出功能20print(123) # print 单纯打印a = "20"print(a)

**compile:**将字符串类型的代码编译。代码对象能够通过exec语句来执行或者eval()进行求值。

参数说明**:**

1. 参数source:字符串或者AST(Abstract Syntax Trees)对象。即需要动态执行的代码段。

2. 参数 filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。当传入了source参数时,filename参数传入空字符即可。

3. 参数model:指定编译代码的种类,可以指定为 ‘exec’,’eval’,’single’。当source中包含流程语句时,model应指定为‘exec’;当source中只包含一个简单的求值表达式,model应指定为‘eval’;当source中包含了交互式命令语句,model应指定为’single’。

>>> #流程语句使用exec>>> code1 = 'for i in range(0,10): print (i)'>>> compile1 = compile(code1,'','exec')>>> exec (compile1)37>>> #简单求值表达式用eval>>> code2 = '1 + 2 + 3 + 4'>>> compile2 = compile(code2,'','eval')>>> eval(compile2)>>> #交互语句用single>>> code3 = 'name = input("please input your name:")'>>> compile3 = compile(code3,'','single')>>> name #执行前name变量不存在Traceback (most recent call last):File "<pyshell#29>", line 1, in <module>nameNameError: name 'name' is not defined>>> exec(compile3) #执行时显示交互命令,提示输入please input your name:'pythoner'>>> name #执行后name变量有值"'pythoner'"

3 输出相关

**input():**获取用户输入

**print():**打印输出

def print(self, *args, sep=' ', end='\n', file=None): # known special case of print"""print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)file: 默认是输出到屏幕,如果设置为文件句柄,输出到文件sep: 打印多个值之间的分隔符,默认为空格end: 每一次打印的结尾,默认为换行符flush: 立即把内容输出到流文件,不作缓存"""print源码剖析

import timefor i in range(0,101,2): time.sleep(0.1)char_num = i//2#打印多少个'*'per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i == 100 else '\r%s%% : %s'%(i,'*'*char_num)print(per_str,end='', flush=True)#小越越 : \r 可以把光标移动到行首但不换行打印进度条

4 数据类型相关

**type(a):**返回变量a的数据类型

5 内存相关

**id(a)😗*返回参数a的内存地址

**hash(a):**a是参数,返回一个可hash变量的哈希值,不可hash的变量会报错

hash函数会根据一个内部的算法对当前可hash变量进行处理,返回一个int数字。

*每一次执行程序,内容相同的变量hash值在这一次执行过程中不会发生改变。

t = (1,2,3)l = [1,2,3]print(hash(t)) #可hashprint(hash(l)) #会报错'''结果:TypeError: unhashable type: 'list''''hash实例

6 文件操作相关

**open():**打开一个文件,返回一个文件操作符(文件句柄)

7 模块操作相关

**import😗*导入一个模块

# 第一种直接导入import time# 第二种导入字符串名字os = __import__('os')print(os.path.abspath('.'))# 实际是通过sys模块找到'os'文件的路径,再导入使用

help():在控制台执行help()进入帮助模式,查看任意变量或者变量类型的有关操作

8 调用相关

callable(a):a是参数,查看这个参数是否可调用

如果a是一个函数名,则返回True

def func():passprint(callable(func)) #参数是函数名,可调用,返回Trueprint(callable(123)) #参数是数字,不可调用,返回False

dir():默认查看全局空间内的属性,也可以接受一个参数查看这个参数内的方法或变量

print(dir(list)) #查看列表的内置方法print(dir(int)) #查看整数的内置方法

9 数字相关

数字——数据类型相关:bool, int, float, complex

数字——进制转换:bin, oct, hex

数字——数学运算:abs, divmod, min, max, sum, round, pow

min和max高级用法

'''max比较字典类型的大小'''l = [1, 3, 100, -1, 2]print(max(l))dic = {'age1': 18, 'age2': 12}print(max(dic)) # 比较的是字典的keyprint(max(dic.values())) # 比较的是字典的值,但是不是对应那个键# 结合zip函数比较print(max(zip(dic.values(), dic.keys()))) # 比较字典的值,并显示对应的键100age218(18, 'age1')

'''最终的使用方法。'''people = [{'name': 'alex', 'age': 1000},{'name': 'wupeiqi', 'age': 10000},{'name': 'alex', 'age': 9000},{'name': 'alex', 'age': 18},]print(max(people, key=lambda dic:dic['age']))# max()对可迭代对象的每一个元素比较,key接收元素的获取函数(匿名函数)# min()和max()一样。

10 数据结构相关

序列——列表与元组相关:强转类型:list和tuple

序列——字符串相关:str, format, bytes, bytearray, memoryview, ord, chr, ascii, repr

format(str,格式化范式):格式化函数,

# format('a','>10') # 格式化字符a的输出 # a

bytes():将字符根据编码方式转化成对应编码方式的字节

​ bytearray() 法为python内置函数,其用于返回一个新字节数组。这个数组里的元素是可变的,并且每个元素的值范围: 0 <= x < 256。其语法如下:

class bytearray([source[, encoding[, errors]]])'''如果 source 为整数,则返回一个长度为 source 的初始化数组;如果 source 为字符串,则按照指定的 encoding 将字符串转换为字节序列;如果 source 为可迭代类型,则元素必须为[0 ,255] 中的整数;如果 source 为与 buffer 接口一致的对象,则此对象也可以被用于初始化 bytearray。如果没有输入任何参数,默认就是初始化数组为0个元素。'''>>> s = 'xyz'>>> b = bytearray(str(s),'utf8')>>> print bxyz>>> print b[1]121>>> print b[0]120>>> print b[2]122

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9phJqdeg-1588872144758)(C:\Users\v_xjzxu\AppData\Roaming\Typora\typora-user-images\1588837754248.png)]

chr():返回数字序号在Ascii中对应的字符,65–>A, 97–>a, 122–>z

ord():返回字符在Ascii中对应的数字序号*

ascii():判断内容是否ascii字符集中,在的话返回,不在返回\u…一堆数字

repr():显示的原本的数据,没有任何处理

ret = bytearray('alex',encoding='utf-8')print(id(ret))print(ret[0])ret[0] = 65print(ret)print(id(ret))bytearray(b'alex')97bytearray(b'Alex')1976654977712

11 数据集合

数据集合:——字典和集合:dict, set, frozenset

len(): 计算可迭代类型的长度

enumerate(iter[,x]): 枚举,遍历可迭代对象,返回每个对象并为其加上序号,x为序号起始数,默认为0

li = [1,2,3,4]for index,element in enumerate(li,0):print(index,element)0 11 22 33 4

all(): 判断可迭代类型中的所有元素是否都为真,是返回True,任意为假返回false

any(): 判断可迭代类型中元素是否有一个为真,是返回True,全为假返回false

zip(拉链):跟拉链一样,将两个可迭代类型中的元素一一对应,包裹在元组里,放在列表中

print(list(zip(('q', 'b', 'c'), (1, 2, 3)))) # [('q', 1), ('b', 2), ('c', 3)]print(list(zip(('abcd'), ('123')))) # [('a', '1'), ('b', '2'), ('c', '3')]# 可以拼接多个可迭代对象。不止两个

slice(): 切片

l = 'hello's1 = slice(3, 5) # l[s1] = l[3, 5]s2 = slice(1, 4, 2) # l[s2] = l[1, 4, 2]print(l[s1])print(l[s2])

12 sorted方法

给列表排序的两个方法(前提,列表中元素可比较)

方法1.用List的成员函数sort进行排序,在本地进行排序,不返回副本

方法2.用built-in函数sorted进行排序(从2.4开始),返回副本,原始输入不变

参数说明:

iterable:是可迭代类型;

key:传入一个函数名,函数的参数是可迭代类型中的每一项,根据函数的返回值大小排序;

reverse:排序规则. reverse = True 降序 或者 reverse = False 升序,有默认值。

返回值:有序列表

people = [{'name': 'alex', 'age': 1000},{'name': 'wupeiqi', 'age': 10000},{'name': 'alex', 'age': 9000},{'name': 'alex', 'age': 18},]print(sorted(people, key=lambda dic:dic['age']))[{'name': 'alex', 'age': 18}, {'name': 'alex', 'age': 1000}, {'name': 'alex', 'age': 9000}, {'name': 'wupeiqi', 'age': 10000}]

二 匿名函数

#这段代码def calc(n):return n**nprint(calc(10))#换成匿名函数calc = lambda n:n**nprint(calc(10))

上面是我们对calc这个匿名函数的分析,下面给出了一个关于匿名函数格式的说明

函数名 = lambda 参数 :返回值#参数可以有多个,用逗号隔开#匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值#返回值和正常的函数一样可以是任意数据类型

我们可以看出,匿名函数并不是真的不能有名字。

匿名函数的调用和正常的调用也没有什么分别。

除此之外,匿名函数也不是浪得虚名,它真的可以匿名。在和其他功能函数合作的时候

l=[3,2,100,999,213,1111,31121,333]print(max(l))dic={'k1':10,'k2':100,'k3':30}print(max(dic))print(dic[max(dic,key=lambda k:dic[k])])# 31121# k3# 100

map(func, iter)

映射函数:

创建一个迭代器,使用可迭代对象的每个参数计算函数并返回。当最短的可迭代用尽时停止。

map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。

注:map函数内部会的机制会自动遍历传进来的可迭代对象。然后对遍历后的元素指定比较规则。(这里理解很重要)

num = [1, 2, 4, 5, 2, 8]# 第一步需求,将列表中的数字全部平方# new_li = []# def square(array):#for i in array:# new_li.append(i**2)#return new_li## print(square(num))# 第二步需求,将列表中的数字全部减一# new_li = []# def reduce(array):#for i in array:# new_li.append(i-1)#return new_li## print(reduce(num))# 当需求过于巨大,需要一个一个实现,此时我们可以定义一个可以使用不同函数作用的函数def square(num):return num**2def reduce(num):return num - 1def map_test(func, array):ret = []for i in array:res = func(i)ret.append(res)return retprint(map_test(square, num))print(map_test(reduce, num))

li = [1, 2, 3, 4, 5]'''def square(num):return num**2# 传入有名函数map(square, li)'''# 传入匿名函数map(lambda x:x**2, li)print(list(map(lambda x:x**2, li)))# 结果[1, 4, 9, 16, 25]

filter(func, iter): 过滤函数

返回一个迭代器,产生函数(item)为true的iterable项。如果function为None,则返回结果为true的项。

# 请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:sqrt=[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]import mathdef is_sqr(x):return math.sqrt(x) % 1 == 0print(list(filter(is_sqr, range(1, 101))))# 匿名函数写法:# print(list(filter(lambda x:math.sqrt(x)%1==0,range(1,101))))

#过滤掉列表结尾带sbmovie_people = ['sb_alex', 'wupeiqi_sb', 'linhaifeng', 'sb_yuanhao']a=list(filter(lambda x:movie_people[x].endswith('sb') ,range(len(movie_people))))movie_people.remove(movie_people[a[0]])print(movie_people)#['sb_alex', 'linhaifeng', 'sb_yuanhao']

reduce(func, iter)

返回一个结果,将连个参数的函数累积到序列的项上,从做到右,以便将序列减少到单个值

- 为了快速的进行累加,连乘的计算,使代码更简洁

from functools import reduce

# reduce的推导过程numbers = [1, 2, 3, 100]# 需求1,将列表中元素累乘res = 1for num in numbers:res *= numprint(res)# 需求2,封装成函数def reduce_test(array):res = 1for num in array:res *= numreturn resprint(reduce_test(numbers))# 需求3,要求功能可变,并置顶初始参数def multi(x, y):return x*y# 等价于lambda x,y:x*ydef reduce_test(func, numbers, init=None):if init is None:res = 1else:res = initfor num in numbers:res = func(res, num)return resprint(reduce_test(lambda x,y:x*y, numbers, 10))

# reduce的使用from functools import reduceli = [1,2,3,4,5]print(reduce(lambda x,y:x*10+y, li))'''过程:x=1,y=2 >>> x*10+y = 1*10+2 = 12, 并将12赋值给x,y取值3 >>> x*10+y = 12*10+3 = 123, 并将123赋值给x,y取值4依次下去,最后-->12345'''

三 模块

**模块的本质:**一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里。

这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。

在Python中,一个.py文件就称之为一个模块(Module)

1 collections**模块

在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。

namedtuple: 生成可以使用名字来访问元素内容的tupledeque: 双端队列,可以快速的从另外一侧追加和推出对象Counter: 计数器,主要用来计数OrderedDict: 有序字典defaultdict: 带有默认值的字典

2 namedtuple 命名元组

我们知道tuple``可以表示不变集合,例如,一个点的二维坐标就可以表示成:

p = (1,2)

但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。

这时,nametuple就派上了用场:nametuple可以为元素的每一个元素名一个名字,这样可以区分元组中的每个元素的意义

from collections import namedtuplePoint = namedtuple('Point', ['x', 'y']) # 获得一个命名元组类p = Point(1, 2) # 为这个类实例化一个对象# p.x 通过名字取值# p.ytu = namedtuple('self',['name','age','gender','hobby'])# 获得一个类t = tu('self',29,'male', 'programing, prography')# 实例化一个对象print(t)print(t.name)# self(name='self', age=29, gender='male', hobby='programing, prography')# self

3 deque 双端队列

使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

双端队列和列表的区别:

效率不同底层的数据结构上,列表先进先出(FIFO),栈先进后出(LIFO)

两者的特点:

双端队列:链表式数据结构,存入值速度快列表:取值,根据索引,双端队列要一个一个往下找。

使用场景:

从中间插入或者删除比较频繁,使用双端队列单纯的append和pop最后一个元素的时候,用列表。

列表的用法,尽量只用append和pop

from collections import dequed = deque([1,2,3,4])# 右侧添加d.append(5) # deque([1, 2, 3, 4, 5])# print(d)# 左侧添加d.appendleft(10) # deque([10, 1, 2, 3, 4, 5])# print(d)# 插入d.insert(2,99) # deque([10, 1, 99, 2, 3, 4, 5])print(d)# 删除a=[1]d.remove(d[a[0]]) # 指定元素删除print(d)d.pop() # 不可根据索引删除,因为是双向的

deque除了实现list的append()pop()外,还支持appendleft()popleft(),这样就可以非常高效地往头部添加或删除元素。

4 defaultdict 默认字典

# 默认字典d = defaultdict(list) # defaultdict(<class 'list'>, {})# print(d)d['name'] # defaultdict(<class 'list'>, {'name': []})print(d)

有如下值集合 [11,22,33,44,55,66,77,88,99,90…],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。

即: {‘k1’: 大于66 , ‘k2’: 小于66}

values = [11, 22, 33,44,55,66,77,88,99,90]my_dict = {}for value in values:if value>66:if 'k1' in my_dict:my_dict['k1'].append(value)else:my_dict['k1'] = [value]else:if 'k2' in my_dict:my_dict['k2'].append(value)else:my_dict['k2'] = [value]print(my_dict) #{'k2': [11, 22, 33, 44, 55, 66], 'k1': [77, 88, 99, 90]}

from collections import defaultdictvalues = [11, 22, 33,44,55,66,77,88,99,90]my_dict = defaultdict(list)for value in values:if value>66:my_dict['k1'].append(value)else:my_dict['k2'].append(value)print(my_dict)#defaultdict(<class 'list'>, {'k2': [11, 22, 33, 44, 55, 66], 'k1': [77, 88, 99, 90]})

使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdic:

**默认字典使用场景:**当遇到很多列表类型数据,发现他们的首个元素相同,要合并他们后面的元素进行相应操作,用defaultdict,相当好用。

>>> from collections import defaultdict>>> dd = defaultdict(lambda: 'N/A')>>> dd['key1'] = 'abc'>>> dd['key1'] # key1存在'abc'>>> dd['key2'] # key2不存在,返回默认值'N/A'# 默认字典中设置默认的具体值d = defaultdict(lambda :5)print(['a'])

5 Counter** 计数

Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。

c = Counter('abcdeabcdabcaba')print c输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})总结:没有什么大用处

6.time**模块

在处理和时间相关的问题时候我们需要用到时间模块,时间模块有很多种,这里介绍三种:time模块,datetime模块,dateutil模块

但是本质上,datetime和dateutil都是基于time模块上实现的。

时间相关概念

时间戳

时间是格林威治时间1970年01月01日00时00分00秒

时间戳转换网站:/Tools/unixtime.aspx

时区:

世界各地根据经度的不同划分为24个时区,以英国为零时区,向东向西各划分12个

UTC时间:

协调世界时(coordinated Universal Time,简称UTC)是最主要的世界时间标准,以原子时秒长为标准,在时刻上尽量接近格林威治时间。

比如本地时间比UTC快,如大陆比UTC时间快8小时,则会写作UTC+8,相反写做UTC-10

python中的时间

1.时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。

2.结构化时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

索引(Index) 属性(Attribute) 值(Values)0 tm_year(年) 比如1 tm_mon(月) 1 - 122 tm_mday(日) 1 - 313 tm_hour(时) 0 - 234 tm_min(分) 0 - 595 tm_sec(秒) 0 - 606 tm_wday(weekday) 0 - 6(0表示周一)7 tm_yday(一年中的第几天) 1 - 3668 tm_isdst(是否是夏令时) 默认为0

3.格式化时间(format_time):如-02-14 10:25:00

格式化时间字符串化对应表%Y Year with century as a decimal number.%m Month as a decomal number [01,12].%d Day of the month as a decomal number [01, 31].%H Hour (24-hour clock) as a decimal number [00,23].%M Minute as a decimal number [00,59].%S Second as a decimal number [00,61].%z Time zone offset from UTC.%a Locale's abbreviated weekday name. # 星期的缩写%A Locale's full weekday name. # 星期的全写%b Locale's abbreviated month name. # 月份的缩写%B Locale's full month name. # 月份的全写%X Locale's appropriate time representation. # 冒号分割的时间

time模块的常用方法
time.time(): 获得当前时间的时间戳time.localtime(timestamp): 获得当前时间的结构化时间,参数默认当前时间的时间戳,可以自己给time.strftime(format,struct_time): 将结构化时间,转成格式化时间格式,format可以任意规定,当时要根据对应表time.strptime(string_time,format): 将格式化时间转换成结构化时间struct_timetime.mktime(struct_time): 将结构化时间转换成时间戳time.sleep(second): 休眠多少秒。time.gmtime([sec]): 和localtime方法类似,gmtime是将一个时间转换为UTC时区的struct_time

#导入时间模块>>>import time#时间戳>>>time.time()1500875844.800804#时间字符串>>>time.strftime("%Y-%m-%d %X")'-07-24 13:54:37'>>>time.strftime("%Y-%m-%d %H-%M-%S")'-07-24 13-55-04'#时间元组:localtime将一个时间戳转换为当前时区的struct_timetime.localtime()time.struct_time(tm_year=, tm_mon=7, tm_mday=24,tm_hour=13, tm_min=59, tm_sec=37, tm_wday=0, tm_yday=205, tm_isdst=0)

小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的。

几种格式之间的转换

#时间戳-->结构化时间#time.gmtime(时间戳) #UTC时间,与英国伦敦当地时间一致#time.localtime(时间戳) #当地时间。例如我们现在在北京执行这个方法:与UTC时间相差8小时,UTC时间+8小时 = 北京时间 >>>time.gmtime(1500000000)time.struct_time(tm_year=, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)>>>time.localtime(1500000000)time.struct_time(tm_year=, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)#结构化时间-->时间戳#time.mktime(结构化时间)>>>time_tuple = time.localtime(1500000000)>>>time.mktime(time_tuple)1500000000.0

#结构化时间-->字符串时间#time.strftime("格式定义","结构化时间") 结构化时间参数若不传,则显示当前时间>>>time.strftime("%Y-%m-%d %X")'-07-24 14:55:36'>>>time.strftime("%Y-%m-%d",time.localtime(1500000000))'-07-14'#字符串时间-->结构化时间#time.strptime(时间字符串,字符串对应格式)>>>time.strptime("-03-16","%Y-%m-%d")time.struct_time(tm_year=, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1)>>>time.strptime("07/24/","%m/%d/%Y")time.struct_time(tm_year=, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=205, tm_isdst=-1)

#结构化时间 --> %a %b %d %H:%M:%S %Y串#time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串>>>time.asctime(time.localtime(1500000000))'Fri Jul 14 10:40:00 '>>>time.asctime()'Mon Jul 24 15:18:33 '#时间戳 --> %a %b %d %H:%M:%S %Y串#time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串>>>time.ctime()'Mon Jul 24 15:19:07 '>>>time.ctime(1500000000)'Fri Jul 14 10:40:00 '

7 datetime模块

官方文档:http://devdocs.io/python~3.6/library/datetime /3/library/time.html#strftime-and-strptime-behavior

由于time模块在时间的加减上很不友好,所以有人写出的datetime模块,time模块是datetime模块的底层模块

datetime包中常用的几个模块

from datetime import datetimefrom datetime import timedeltafrom datetime import date

from datetime import datetime# datetime.now(): 获取当前时间print(datetime.now()) # -03-20 11:38:31.423739# datetime.timestamp(): 将当前时间转成时间戳time_stamp = datetime.timestamp(datetime.now())print(time_stamp)# datetime.strftime(struct_time,format):将结构化时间转换成格式化字符串时间f = datetime.strftime(datetime.now(),'%Y-%m-%d %X')print(f)# datetime.strptime(string_time,format): 将字符串时间转换成格式化时间。t = datetime.strptime(f,'%Y-%m-%d %H:%M:%S')print(t)

使用timedelta生成时间间隔,用时间的计算

from datetime import timedeltad = timedelta(days=1,hours=5) # 根据参数,生成多少间隔的一个时间间隔对象print(d) # 1 day, 5:00:00# timedelta(): 获取时间差额,用于datetime的增减计算。用时间对象与timedelta运算。print(datetime.now()-timedelta(days=2)) # -03-18 16:45:04.427857

8 date模块

from datetime import date,timedeltatoday = date.today()d = timedelta(days=1, hours=5)future = today + dprint(future)

9 dateutil模块

第三方库:pip install python-dateutil

官方文档:https://dateutil.readthedocs.io/en/stable/examples.html#relativedelta-examples

原因:timedelta不够用,处理跨星期,跨月,跨年的计算麻烦

class datetime.timedelta(days=0, seconds=0, microseconds=0,milliseconds=0, minutes=0, hours=0, weeks=0)

# 下周的星期三是几号from datetime import datetimefrom dateutil.relativedelta import relativedeltafrom dateutil.rrule import * # MO,TU,WE,TH,FRd = datetime.now()print(d + relativedelta(weekday=WE)) # 这周print(d + relativedelta(weekday=WE, weeks=+1)) # 下周print(d + relativedelta(weekday=WE, weeks=-1)) # 上周

计算过了一个月,或者三个月后是哪一天?不能简单+30

from datetime import datedate(, 1, 31) + relativedelta(months=+1)date(,1,25) + relativedelta(months=-10)

10 random模块**:

随机数模块:产生随机数

random.random(): 返回0-1之间的随机小数random.randint(a,b): 返回从a到b之间的随机整数,闭区间random.uniform(a,b): 返回arandom.randrange(m,n,k): 返回m到n步长为k的整数,前开后闭区间random.choice(有序的iterable): 从有序的可迭代对象中随机选择一个元素random.choices(有序的iterable,k=num): 从有序的可迭代对象中随机选取多个元素,个数可指定,元素之间可重复random.sample(有序的iterabel,k=num): 从有序的可迭代对象中随机选取多个元素,个数可指定,元素之间不重复random.shuffle(iterable): 将有序可迭代对象中的元素打乱顺序。

>>> import random#随机小数>>> random.random()# 大于0且小于1之间的小数0.7664338663654585>>> random.uniform(1,3) #大于1小于3的小数1.6270147180533838#恒富:发红包#随机整数>>> random.randint(1,5) # 大于等于1且小于等于5之间的整数>>> random.randrange(1,10,2) # 大于等于1且小于10之间的奇数#随机选择一个返回>>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5]#随机选择多个返回,返回的个数为函数的第二个参数>>> random.sample([1,'23',[4,5]],2) # #列表元素任意2个组合[[4, 5], '23']#打乱列表顺序>>> item=[1,3,5,7,9]>>> random.shuffle(item) # 打乱次序>>> item[5, 1, 3, 7, 9]>>> random.shuffle(item)>>> item[5, 9, 7, 1, 3]

练习:

生成随机验证码

import randomdef v_code():code = ''for i in range(5):num=random.randint(0,9)alf=chr(random.randint(65,90))add=random.choice([num,alf])code="".join([code,str(add)])return codeprint(v_code())

11 os模块**

概念:内置模块,是与当前电脑操作系统做交互的一个接口

常用方法
1.文件相关

os.makedirs('dirname1/dirname2') 可生成多层递归目录os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirnameos.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirnameos.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印

2.文件相关

os.remove() 删除一个文件os.rename("oldname","newname") 重命名文件/目录os.stat('path/filename') 获取文件/目录信息

3.环境相关

os.system("bash command") 运行shell命令,直接显示os.popen("bash command).read() 运行shell命令,获取执行结果os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd

4.路径相关(重要)

os.pathos.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不存在,返回Falseos.path.isabs(path) 如果path是绝对路径,返回Trueos.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回Falseos.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回Falseos.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间os.path.getsize(path) 返回path的大小

注意:os.stat(‘path/filename’) 获取文件/目录信息 的结构说明

stat 结构:st_mode: inode 保护模式st_ino: inode 节点号。st_dev: inode 驻留的设备。st_nlink: inode 的链接数。st_uid: 所有者的用户ID。st_gid: 所有者的组ID。st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。st_atime: 上次访问的时间。st_mtime: 最后一次修改的时间。st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。

os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"os.linesep 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

12 sys模块 **

概念:sys模块是与python解释器交互的一个接口

常用方法
sys.argv: 实现从程序外部向程序传递参数。sys.exit([arg]): 程序中间的退出,arg=0为正常退出。sys.path: 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值sys.platform: 获取当前系统平台。sys.version:获取Python解释程序的版本信息sys.modules 返回系统导入的模块字段,key是模块名,value是模块sys.stdout, sys.stdin, sys.stderror:分别和输出输入,错误输出相关。sys.stdout.write和print 都是输出相关的函数print内部也是调用的sys.stdout,sys.stdout默认输出是屏幕。
sys.argv方法

在外部向程序内部传递参数,sys.argv是命令行参数列表,第一个元素是程序本身

# 当我们在命令行cmd中运行某一个文件,后面可以附带参数,这些附带的参数就可以通过sys.argv获得。比如我们在cmd中输入 python test.py post C://test ,然后我们在test.py文件中打印sys.argv就可以拿到后面的参数post和C://testimport sysprint(sys.argv)# 运行结果['D:/PyCharmProject/python全栈S20/01-test/test.py', post, C://test] # 列表第一个参数是脚本本身

sys.exit(n)

功能:执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.exit函数,带有一个可选的整数参数返回给调用它的程序,表示你可以在主程序中捕获对sys.exit的调用。(0是正常退出,其他为异常)

import sysprint('hello')sys.exit(0)print('python')# 运行程序后发现在,程序输出hello后并没有继续输出python。因为在执行到sys.exit(0)的时候程序就结束了。

sys.stdout()

import syssys.stdout.write(str)

sys.stdout.write()的打印会将结果先缓存,知道所有结果都在缓存中然后一起打印,如果想挨个显示自己的,可以使用sys.stdout.flush()来逐个刷新。没打印一个就刷新屏幕显示。

sys.stdout和print

import syss = 'test stdout'print('--')sys.stdout.write(s)print('--')class A(object):passprint(A) # 正常sys.stdout.write(A) # 报错

注意:print 什么类型都可以输出,但是sys.stdout.write只可以输出字符串类型,否则报错。print默认是最后换行,但是sys.stdout.write默认不换行。

import sysfile = sys.stdout # 存储原始的输出对象sys.stdout = open('1.txt', 'w') # 重定向所有的写入内容到 1.txt 文件,print('Citizen_Wang') # 写入到 1.txt 文件中,在上一行语句中改变了输出流到文件中print('Always fall in love with neighbours') # 继续写入到文件中sys.stdout.close() # 其实就是 open 文件之后的关闭sys.stdout = file # 将 print 命令的结果返回给控制台print('输出信息返回在控制台') # 该信息会在控制台也显示

13.序列化模块**

什么叫序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化

我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,

在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

'''比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,但是你要怎么把一个字符串转换成字典呢?聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。BUT!强大的函数有代价。安全性是其最大的缺点。想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。而使用eval就要担这个风险。所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)'''

序列化的目的:

1、以某种存储形式使自定义对象持久化;

2、将对象从一个地方传递到另一个地方。

3、使程序更具维护性。

把具有复杂结构(引用关系)的数据结构由一种立体结构变成一种线性结构保存在文件中或者是通过网络传输.

如果只是普通的字符串或者是数值等简单的数据类型,不需要序列化,也能完成保存或者是网络传输.

json模块

json数据:用于多种语言交互,编程语言通用数据内置的,不需要安装,直接导入使用,数据持久化

json的四种方法:

dumps():序列化,将一个字典转换成一个字符串loads():反序列化,将一个字符串格式的字典转换成一个字典dump(对象,文件句柄):接收一个文件句柄,直接将字典转换成json字符串写入文件load(文件句柄):接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回

import jsondic = {'k1':'v1','k2':'v2','k3':'v3'}str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}#注意,json转换完的字符串类型的字典中的字符串是由""表示的dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型 print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]list_dic2 = json.loads(str_dic)print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]loads和dumps

import jsonf = open('json_file','w')dic = {'k1':'v1','k2':'v2','k3':'v3'}json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件f.close()f = open('json_file')dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回f.close()print(type(dic2),dic2)

import jsonf = open('file','w')json.dump({'国籍':'中国'},f)ret = json.dumps({'国籍':'中国'})f.write(ret+'\n')json.dump({'国籍':'美国'},f,ensure_ascii=False)ret = json.dumps({'国籍':'美国'},ensure_ascii=False)f.write(ret+'\n')f.close()

Json 源码

Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:将数据根据keys的值进行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

import jsondata = {'username':['李华','二愣子'],'sex':'male','age':16}json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)print(json_dic2)

json注意点:

1.json写入时,只能一次性写入,无论多少数据只能套入一个字典中写入,所以不支持追加写入

2.json在文件中不认单引号。

3.无论数据怎么创建,只要满足json格式,就可以用json.loads出来。

pickle模块

json和pickle的区别

json,用于json字符串 和 字典数据类型进行转换pickle,用于python中所有类型数据的文本化,持久化

pickle模块提供了四个功能:

dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表…可以把python中任意的数据类型序列化

dumps(): 将python对象转换成字节数据loads(): 将字节数据转换成python对象dump(obj,文件句柄):将python对象转换成字节数据并写入文件,注意写入方式要用’wb’,而且不能指定编码。load(文件句柄): 将文件中的字节数据读取出来并转换成python对象

注:dump,load有持久化特点,将代码存入文件永久保存。

# dumps(): 将对象(字典数据)转换成字节数据dic = {'name': 'ryxiong', 'age': 18}print(pickle.dumps(dic)) # b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x07\x00\x00\x00ryxiongq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'# loads(): 将字节数据的数据转换成对象(字典数据)b = b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x07\x00\x00\x00ryxiongq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'print(pickle.loads(b))# dump(obj,文件句柄):将对象(字典数据)转换成字节数据并写入文件,注意写入方式要用'wb',而且不能指定编码。pickle.dump(dic,open('pickle.txt', 'wb'))# load(文件句柄): 将文件中的字节数据读取出来并转换成对象(字典数据)data = pickle.load(open('pickle.txt','rb'))print(data)

这时候机智的你又要说了,既然pickle如此强大,为什么还要学json呢?

这里我们要说明一下,json是一种所有的语言都可以识别的数据结构。

如果我们将一个字典或者序列化成了一个json存在文件里,那么java代码或者js代码也可以拿来用。

但是如果我们用pickle进行序列化,其他语言就不能读懂这是什么了~

所以,如果你序列化的内容是列表或者字典,我们非常推荐你使用json模块

但如果出于某种原因你不得不序列化其他的数据类型,而未来你还会用python对这个数据进行反序列化的话,那么就可以使用pickle。

shelve模块

shelve:返回类似字典的对象,可读可写,key必须是字符串,值可是任何类型

shelve只有一个方法:

open():返回类似字典的对象,可读可写,key必须是字符串,值可是任何类型

import shelvef = shelve.open(r'shelve.txt')f['name'] = 'ryxiong'f['age'] = 26f['hobby'] = {'hobby1':'prograhpy', 'hobby2':'reading'}print(f['name'])print(f['hobby'])f.close()# print(f['hobby']) # 报错,文件已关闭,无法操作# 注:如果遇到字典写不进去的问题,在open()参数中增加参数writeback=True。f = shelve.open(r'shelve.txt',writeback=True)

14 logging 日志模块**

日志的作用:

用来记录程序中的重要的操作,或者检测程序是否和预想一样执行

logging两种方法:函数式简单配置,logger对象配置

函数式简单配置

import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')

默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。

简单配置法缺点:

中文显示乱码

不能同时输出到文件和屏幕

灵活配置日志级别,日志格式,输出位置:

默认级别为warning,默认打印到终端

import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')

为logging模块指定全局配置,针对所有logger有效,控制打印到文件中

配置参数

可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。#格式%(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:字符串形式的当前时间。默认格式是 “-07-08 16:49:45,896”。逗号后面的是毫秒%(thread)d:线程ID。可能没有%(threadName)s:线程名。可能没有%(process)d:进程ID。可能没有%(message)s:用户输出的消息logging.basicConfig()

logger对象配置

'''logger对象法步骤:1.创建logger对象2.创建一个文件操作符3.创建一个屏幕操作符4.创建一个格式5.logger 绑定文件操作符6.logger 绑定屏幕操作符7.文件操作符 绑定格式8.屏幕操作符 绑定格式'''import logging# 1.创建logger对象logger = logging.getLogger()logger.setLevel(logging.DEBUG)# 2.创建一个文件操作符fh = logging.FileHandler('log',encoding='utf-8')# 3.创建一个屏幕操作符sh = logging.StreamHandler()# 4.创建一个格式fmt = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')# 5.给logger绑定文件操作符logger.addHandler(fh)# 6.给logger绑定屏幕操作符logger.addHandler(sh)# 7.给文件操作符绑定格式fh.setFormatter(fmt)# 8.给屏幕操作符绑定格式sh.setFormatter(fmt)logger.debug('logger debug message')logger.info('logger info message')logger.warning('logger warning message')logger.error('logger error message')logger.critical('logger critical message')

logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过

fh.setLevel(logging.Debug)单对文件流设置某个级别。

logging模块的四大天王

Formatter,Handler,Logger,Filter

#logger:产生日志的对象#Filter:过滤日志的对象#Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端#Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式

区别

'''critical=50error =40warning =30info = 20debug =10'''import logging#1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出logger=logging.getLogger(__file__)#2、Filter对象:不常用,略#3、Handler对象:接收logger传来的日志,然后控制输出h1=logging.FileHandler('t1.log') #打印到文件h2=logging.FileHandler('t2.log') #打印到文件h3=logging.StreamHandler() #打印到终端#4、Formatter对象:日志格式formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',)formmater2=logging.Formatter('%(asctime)s : %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',)formmater3=logging.Formatter('%(name)s %(message)s',)#5、为Handler对象绑定格式h1.setFormatter(formmater1)h2.setFormatter(formmater2)h3.setFormatter(formmater3)#6、将Handler添加给logger并设置日志级别logger.addHandler(h1)logger.addHandler(h2)logger.addHandler(h3)logger.setLevel(10)#7、测试logger.debug('debug')logger.info('info')logger.warning('warning')logger.error('error')logger.critical('critical')

Logger与Handler的级别

logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,但是需要注意的是

重要,重要,重要:

Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO).#验证import loggingform=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',)ch=logging.StreamHandler()ch.setFormatter(form)# ch.setLevel(10)ch.setLevel(20)l1=logging.getLogger('root')# l1.setLevel(20)l1.setLevel(10)l1.addHandler(ch)l1.debug('l1 debug')

Logger的继承(了解)

import loggingformatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',)ch=logging.StreamHandler()ch.setFormatter(formatter)logger1=logging.getLogger('root')logger2=logging.getLogger('root.child1')logger3=logging.getLogger('root.child1.child2')logger1.addHandler(ch)logger2.addHandler(ch)logger3.addHandler(ch)logger1.setLevel(10)logger2.setLevel(10)logger3.setLevel(10)logger1.debug('log1 debug')logger2.debug('log2 debug')logger3.debug('log3 debug')'''-07-28 22:22:05 PM - root - DEBUG -test: log1 debug-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug'''

应用
logging配置

"""logging配置"""import osimport logging.config# 定义三种日志输出格式 开始standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'# 定义日志输出格式 结束logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录logfile_name = 'all2.log' # log文件名# 如果不存在定义的日志目录就创建一个if not os.path.isdir(logfile_dir):os.mkdir(logfile_dir)# log文件的全路径logfile_path = os.path.join(logfile_dir, logfile_name)# log配置字典LOGGING_DIC = {'version': 1,'disable_existing_loggers': False,'formatters': {'standard': {'format': standard_format},'simple': {'format': simple_format},},'filters': {},'handlers': {#打印到终端的日志'console': {'level': 'DEBUG','class': 'logging.StreamHandler', # 打印到屏幕'formatter': 'simple'},#打印到文件的日志,收集info及以上的日志'default': {'level': 'DEBUG','class': 'logging.handlers.RotatingFileHandler', # 保存到文件'formatter': 'standard','filename': logfile_path, # 日志文件'maxBytes': 1024*1024*5, # 日志大小 5M'backupCount': 5,'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了},},'loggers': {#logging.getLogger(__name__)拿到的logger配置'': {'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕'level': 'DEBUG','propagate': True, # 向上(更高level的logger)传递},},}def load_my_logging_cfg():logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置logger = logging.getLogger(__name__) # 生成一个log实例logger.info('It works!') # 记录该文件的运行状态if __name__ == '__main__':load_my_logging_cfg()

使用

"""MyLogging Test"""import timeimport loggingimport my_logging # 导入自定义的logging配置logger = logging.getLogger(__name__) # 生成logger实例def demo():logger.debug("start range... time:{}".format(time.time()))logger.info("中文测试开始。。。")for i in range(10):logger.debug("i:{}".format(i))time.sleep(0.2)else:logger.debug("over range... time:{}".format(time.time()))logger.info("中文测试结束。。。")if __name__ == "__main__":my_logging.load_my_logging_cfg() # 在你程序文件的入口加载自定义logging配置demo()

关于如何拿到logger对象详细解释

注意注意注意:#1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理#2、我们需要解决的问题是:1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC)2、拿到logger对象来产生日志logger对象都是配置到字典的loggers 键对应的子字典中的按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的于是我们要获取不同的logger对象就是logger=logging.getLogger('loggers子字典的key名')但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key 'loggers': {'l1': {'handlers': ['default', 'console'], #'level': 'DEBUG','propagate': True, # 向上(更高level的logger)传递},'l2: {'handlers': ['default', 'console' ], 'level': 'DEBUG','propagate': False, # 向上(更高level的logger)传递},'l3': {'handlers': ['default', 'console'], #'level': 'DEBUG','propagate': True, # 向上(更高level的logger)传递},}#我们的解决方式是,定义一个空的key'loggers': {'': {'handlers': ['default', 'console'], 'level': 'DEBUG','propagate': True, },}这样我们再取logger对象时logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置

15 configparser模块

使用类似键值对套键值对的方式在文件中储存数据。文件是一个大字典,每一块是字典的键,每一块下面的键值对又是一个字典,作为每一个块的值。

配置文件样式如下

# 注释1# 注释2[section1]k1 = v1k2:v2user=egonage=18is_admin=truesalary=31[section2]k1 = v1

读取操作

import configparserconfig=configparser.ConfigParser()config.read('a.cfg')#查看所有的标题res=config.sections() #['section1', 'section2']print(res)#查看标题section1下所有key=value的keyoptions=config.options('section1')print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']#查看标题section1下所有key=value的(key,value)格式item_list=config.items('section1')print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]#查看标题section1下user的值=>字符串格式val=config.get('section1','user')print(val) #egon#查看标题section1下age的值=>整数格式val1=config.getint('section1','age')print(val1) #18#查看标题section1下is_admin的值=>布尔值格式val2=config.getboolean('section1','is_admin')print(val2) #True#查看标题section1下salary的值=>浮点型格式val3=config.getfloat('section1','salary')print(val3) #31.0

写入操作

import configparserconfig=configparser.ConfigParser()config.read('a.cfg',encoding='utf-8')#删除整个标题section2config.remove_section('section2')#删除标题section1下的某个k1和k2config.remove_option('section1','k1')config.remove_option('section1','k2')#判断是否存在某个标题print(config.has_section('section1'))#判断标题section1下是否有userprint(config.has_option('section1',''))#添加一个标题config.add_section('egon')#在标题egon下添加name=egon,age=18的配置config.set('egon','name','egon')config.set('egon','age',18) #报错,必须是字符串#最后将修改的内容写入文件,完成最终的修改config.write(open('a.cfg','w'))

练习

基于上述方法添加一个ini 文档

import configparserconfig = configparser.ConfigParser()config["DEFAULT"] = {'ServerAliveInterval': '45','Compression': 'yes','CompressionLevel': '9'}config[''] = {}config['']['User'] = 'hg'config[''] = {}topsecret = config['']topsecret['Host Port'] = '50022'# mutates the parsertopsecret['ForwardX11'] = 'no' # same hereconfig['DEFAULT']['ForwardX11'] = 'yes'with open('example.ini', 'w') as configfile:config.write(configfile)

16.hashlib模块**

'''概念'''1、什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值2、hash值的特点是:只要传入的内容一样,得到的hash值必然一样=====>要用明文传输密码文件完整性校验不能由hash值返解成内容=======》把密码做成hash值,不应该在网络传输明文密码只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

md5和sha的区别:

md5:速度快,但是现在容易被破解

sha:密文长,更安全,但是速度慢

'''md5加密'''import hashlibm = hashlib.md5() # m=hashlib.sha256()# 选择加密方式,获取一个加密对象print(m) # <md5 HASH object @ 0x000001F0F0807558>m.update('hello'.encode('utf-8')) # 将明文转成字节然后加密print(m.hexdigest()) # 5d41402abc4b2a76b9719d911017c592

注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样

但是update多次为校验大文件提供了可能。

以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

加盐加密

'''md5加密+加盐'''m1 = hashlib.md5('盐'.encode('utf-8')) # 这一步相当于给密码加盐m1.update('passwd'.encode('utf-8'))'''256加密'''sha = hashlib.sha256('hello'.encode('utf-8')) # 这一步相当于给密码加盐sha.update('alex'.encode('utf-8'))print(sha.hexdigest())

模拟撞库破解密码

import hashlibpasswds=['alex3714','alex1313','alex94139413','alex123456','123456alex','a123lex',]def make_passwd_dic(passwds):dic={}for passwd in passwds:m=hashlib.md5()m.update(passwd.encode('utf-8'))dic[passwd]=m.hexdigest()return dicdef break_code(cryptograph,passwd_dic):for k,v in passwd_dic.items():if v == cryptograph:print('密码是===>\033[46m%s\033[0m' %k)cryptograph='aee949757a2e698417463d47acac93df'break_code(cryptograph,make_passwd_dic(passwds))

17 hmac 模块

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密:

import hmach = hmac.new('alvin'.encode('utf8'))h.update('hello'.encode('utf8'))print (h.hexdigest())#320df9832eab4c038b6c1d7ed73a5940

#要想保证hmac最终结果一致,必须保证:#1:hmac.new括号内指定的初始key一样#2:无论update多少次,校验的内容累加到一起是一样的内容import hmach1=hmac.new(b'egon')h1.update(b'hello')h1.update(b'world')print(h1.hexdigest())h2=hmac.new(b'egon')h2.update(b'helloworld')print(h2.hexdigest())h3=hmac.new(b'egonhelloworld')print(h3.hexdigest())'''f1bf38d054691688f89dcd34ac3c27f2f1bf38d054691688f89dcd34ac3c27f2bcca84edd9eeb86f30539922b28f3981'''

18 suprocess模块

import subprocess'''sh-3.2# ls /Users/egon/Desktop |grep txt$mysql.txttt.txt事物.txt'''res1=subprocess.Popen('ls /Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE)res=subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,stdout=subprocess.PIPE)print(res.stdout.read().decode('utf-8'))#等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grepres1=subprocess.Popen('ls /Users/jieli/Desktop |grep txt$',shell=True,stdout=subprocess.PIPE)print(res1.stdout.read().decode('utf-8'))#windows下:# dir | findstr 'test*'# dir | findstr 'txt$'import subprocessres1=subprocess.Popen(r'dir C:\Users\Administrator\PycharmProjects\test\函数备课',shell=True,stdout=subprocess.PIPE)res=subprocess.Popen('findstr test*',shell=True,stdin=res1.stdout,stdout=subprocess.PIPE)print(res.stdout.read().decode('gbk')) #subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码

四 包

如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。

每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录(文件夹),而不是一个包。init.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是对应包的名字。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。