第一章 python基础
初识
-
cpu 内存 硬盘 操做系统python
cpu:计算机的运算和计算中心,至关于人类大脑。
内存:暂时存储数据,临时加载数据应用程序,运行速度快,高铁,断电即消失,造价很高。
硬盘:磁盘,长期存储数据。
操做系统:一个软件,链接计算机的硬件与全部软件之间的一个软件。
git -
python的编程语言分类web
-
编译型:将代码一次性所有编译成二进制,而后再执行。优势:执行效率高。缺点:开发效率低,不能跨平台。表明语言:C面试
-
解释型:逐行解释成二进制,逐行运行。优势:开发效率高,能够跨平台。缺点:执行效率低。表明语言:python。正则表达式
-
-
python的种类算法
- Cpython:官方推荐解释器。能够转化成C语言能识别的字节码。
- Jpython: 能够转化成Java语言能识别的字节码。
- Ironpython:能够转化成.net语言能识别的字节码
- pypy: 动态编译。
......
-
变量:只是指向某种数据数据库
-
常量:python中没有真正的常量,为了应和其余语言的口味,所有大写的变量称之为常量。编程
-
while/for 的else:若是循环没有被break终止则else语句会被执行,若是while被break终止,则不执行else语句。json
-
运算符:算数运算符+、-等;比较运算符>、==等;赋值运算符=、+=等;逻辑运算符not、and、or;成员运算符in、not in。
and or not
windows- 在没有()的状况下,优先级:not > and > or,同一优先级从左至右依次计算
-
三元运算符:简单的if-else语句能够简化为三元运算符。如判断a,b的大小
c = a if a>b else b
-
编写代码原则:开放封闭原则,代码对于将来的一些拓展必定是要开放的(接口)能够添加一些功能。
开放封闭原则:
开放:对源码的拓展是开放的。
封闭:对源码的修改是封闭的。
*的魔术用法:
*的聚合:用于万能形参,在函数的定义时, *将全部的位置实参聚合成一个元祖,将这个元祖赋值给args。**将全部的关键字参数聚合成一个一个字典,将这个字典赋值给kargs。
*的打散,在函数的调用时*打散的是迭代对象,必须用在可迭代对象上(str,list等)**打散的是字典。
def func(*args): print(args) funs([1,2,3],[4,5,6]) #([1, 2, 3], [4, 5, 6]) funs(*[1,2,3],*[4,5,6]) #*的打散,等同于funs(1, 2, 3, 4, 5, 6) #(1, 2, 3, 4, 5, 6) def func(*args,**kargs): print(args) print(kargs) funs({'百度网盘群': '980173694'}) #({'百度网盘群': '980173694'}) {} funs(**{'百度网盘群': '980173694'})#**的打散,等同于funs(百度网盘群='980173694') #() {'number': '980173694', 'massage': '欢迎加入百度网盘群'}
格式化输出(3.6版本以后)
基础表达:
name = 'python' age = '18' msg = f'我叫{name},今年{age}' #在引号前添加一个字符f
能够加表达式:
count = 2 print(f'最终结果:{count**2}') name = 'python' print(f'个人名字是{name.upper()}') dic = {'name':'python','age':'18'} msg = f'我叫{dic["name"]},今年{dic["age"]}' #注意双引号与单引号的使 list = ['python','18'] msg = f'我叫{list[0]},今年{list[1]}'
能够结合函数:
def sum1(a,b): return a+b print(f'最终结果是{sum1(1,2)}')
优势:1.结构更加优化。2.能够结合表达式和函数使用。3.效率更高
编码
计算机存储文件,存储数据,以及经过网络发送出去,储存发送数据底层都是0与1的二进制。
密码本:0101011001 二进制与文字之间的关系
ASCII码:只包含英文字母,数字,特殊字符。共8位,但只用了7位,能够表示128(2**7)个不一样的字符。ASCII码预留了一位,第8位为0。
字节:8bit(位) = 1byte(字节)
中国:gbk(最多能表示2**16个中文),只包含英文字母,数字,特殊字符(ASCII)和中文,也叫国标(国家标准)。一个英文字母用一个字节表示,一个中文用两个字节。
Unicode:万国码:把世界上的全部的文字都记录到这个密码本。用4个字节表示,可表示2**32=4294967296个文字。
utf-8:(Unicodes升级版本)最少用1个字节表示字符(英语),欧洲用2个字节,中文用3个字节
'咱们12ax' :GBK :8个字节
'咱们12ax' :UTF-8:10个字节
单位的转换:
8bit = 1byte
1024byte = 1kb
1024kb = 1MB
......GB、TB、PB、EB、 ZB 、YB、 NB
不一样的编码方式之间不能相互识别:
-
数据在内存中所有是以Unicode编码的,可是当数据用于网络传输或者存储到硬盘中,必须是以非Unicode编码(utf-八、gbk等)
-
python中的数据从内存(Unicode编码)存储到硬盘或进行网络传输时要经历一个特殊的转化过程,要转化为一个非Unicode编码类型的特殊数据才能进行传输或储存至硬盘,即bytes类型(内存中的编码方式:非Unicode)
-
bytes与str的操做方式大部分都是同样,bytes can only contain ASCII literal characters,bytes用于文件的储存、网络的传输等。直接将非ASCII码字符串转化为bytes类型会报错,要使用
encode()
。#ASCII码中的字符转bytes: a = b'iloveyou' print(a,type(a)) #b'iloveyou' <class 'bytes'> #将中文转化为bytes类型: b = b'山就在那儿' print(b) #SyntaxError: bytes can only contain ASCII literal characters #正确方法为: c = '山就在那儿' b = c.encode('utf-8') print(c.encode('utf-8')) #通常指定utf-8的编码形式, (encode:编码) >>>b'\xe5\xb1\xb1\xe5\xb0\xb1\xe5\x9c\xa8\xe9\x82\xa3\xe5\x84\xbf'
-
bytes可转化为字符串类型(Unicode)(decode,解码)。用什么编码类型转换为bytes数据类型的就用什么解码。
b = b'\xe5\xb1\xb1\xe5\xb0\xb1\xe5\x9c\xa8\xe9\x82\xa3\xe5\x84\xbf' print(b.decode('utf-8')) #山就在那儿 #用什么编码类型转换为bytes数据类型的就用什么解码。 b = b'\xe5\xb1\xb1\xe5\xb0\xb1\xe5\x9c\xa8\xe9\x82\xa3\xe5\x84\xbf' c = b.decode('gbk') print(c) >>>UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 14: incomplete multibyte sequence
小题试作:gbk转换为utf-8
#分析,全部的编码都与Unicode有关(计算机内存中以Unicode编码),所以可先将gbk转换为Unicode编码,再转换为utf-8编码。 gbk = b'\xc9\xbd\xbe\xcd\xd4\xda\xc4\xc7\xb6\xf9' decode1 = gbk.decode('gbk') #解码为Unicode编码的字符串,可print(decode1)查看。 print(decode1.encode('utf-8')) #以utf-8编码 >>>b'\xe5\xb1\xb1\xe5\xb0\xb1\xe5\x9c\xa8\xe9\x82\xa3\xe5\x84\xbf'
数据类型
数据类型的分类(可变与不可变):
- 可变(不可哈希)的数据类型:list dict set(集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),可是集合自己是不可哈希(因此集合作不了字典的键))
- 不可变的数据类型(可哈希): str bool int tuple(该对象自己不可变),(作不可变类型作任何操做,方法都不会改变原对象)
数据之间类型的转换
-
int bool str 三者转换
-
str list 二者转换
-
list set 二者转换
-
str bytes 二者转换,只有字符串能和bytes互换。
-
全部数据均可以转换成bool值,转换成bool值为False的数据类型有:
'',0,(),{},[],set(),None
按照储存空间的占用分(从低到高)
- int
- str
- set : 无序
- tuple: 有序,不可变
- list: 有序,可变
- dict: 有序(3.6版本以后),可变
序列化
结构化数据:内存中的数据是结构化数据,存在许多指针(有指向关系的数据)。将数据组合为有指向关系的数据是结构化的过程。
线性数据:磁盘中的文件是一个典型的线性数据,数据间没有引用关系。
序列化(serialization):将内存中的数据结构(list、str、tuple、dict、set等)转换成字节或字符串,用以保存在文件或经过网络传输,称为序列化过程。
反序列化(deserilzation):从磁盘文件中,网络中获取的数据类型(字节),转换成内存中原来的数据数据结构,称为反序列化过程。
序列化模块:json、pickle、shelve等
软件开发规范
配置文件(conf-setting.py):静态(变量不能改变只能引用)的路径,数据库链接的设置
主逻辑函数(core-src.py):
公共组件(lib-common):装饰器、日志函数、
启动函数(bin-starts.py):只有一个文件。
数据库(db-register):文本数据
日志(log-access.log):日志的数据
READEME
str
存储少许的数据。切片仍是对其进行任何操做,获取的内容全都是str类型,存储的数据单一。
capitalize() 首字母(第一个单词)大写,其他变小写
title() 每一个单词的首字母大写。(以特殊字符(非字母)隔开的即为一个单词)
swapcase() 大小写翻转
center() 居中,有1个必选参数:宽度,一个非必选参数:填充)
find() 经过元素找索引,找到第一个就返回索引,找不到返回-1。
index() 经过元素找索引,找到第一个就返回索引,找不到就报错。
list
列表能够储存大量的数据,但数据间的关联性不强且列表的查询速度比字典慢。
在列表末尾增长一个数据项(list.append()方法),直接修改列表没有返回值。
在列表末尾增长一个数据项集合( 添加多个元素的方法,迭代追加)(list.extend()方法);
l1 = [1,2] l1.extend('abcd') print(l1) >>>[1, 2, 'a', 'b', 'c', 'd'] l2 = [1,2] l2.extend(['asd',1,2]) print(l2) >>>[1, 2, 'asd', 1, 2]
列表的特殊插入法,在特定位置增长一个数据项(list.insert()方法)不推荐使用,下降性能:
a=['b','c','d'] a.insert(0,'a') a[0:1] #['a']
从列表末尾删除数据,按照索引删除(list.pop()方法),若果没有给出索引值则默认删除最后列表的一个元素,有返回值,返回删除的元素,不推荐使用pop(n),下降性能。
l1 = [1,2,3,4] print(l1.pop(0)) #1
在列表中删除一个特定项(list.remove()方法);若是有重复的则默认删除第一个元素(从左开始)
list.clear()清空列表的方法,del 按照索引删除,也能够按照切片删除(可加步长),无返回值
l1 = [1,2,3,4,5,6] del l1[0] print(l1) #[2.3.4,5,6] del l1[0:4:2] print(l1) #[3,5,6]
按照索引改元素;按照切片更改元素(迭代增长),也可按照切片加步长更改,但必须一 一 对应。
l1 = [1,2,3,4] l1[0] = 0 l1[1:] = 'abcd' print(l1) >>>[0, 'a', 'b', 'c', 'd'] l1[::2]='123' print(l1) >>>['1', 'a', '2', 'c', '3']
index() 经过元素找索引
sort() 默认从小到大排序,设置reverse参数则可从小到大。
reverse() 反转
列表相加 (3.4以上版本)
列表与数字相乘 (3.4以上版本)
l1 = [2,'a',[1,'b']] l2 = l1*3 print(l2) >>>[2, 'a', [1, 'b'], 2, 'a', [1, 'b'], 2, 'a', [1, 'b']]
列表的特殊性:正向循环一个列表时若是删除某个元素,那么这个元素后面的全部元素都会向前进一位,它们的索引相比以前也会前进一位,所以,在循环一个列表时的过程当中,若是要改变列表的大小(增长值或者删除值),那么结果极可能会出错或者报错。
l1 = [1,2,3,4,5,6] #删除列表中索引位为偶数的元素。 for i in range(0,len(l1),2): l1.pop(i) print(l1) >>>IndexError: pop index out of range
解决此问题有三种方式:
1.直接删除 (按照元素删除,按照索引删除,切片加步长
#切片加步长 l1 = [1,2,3,4,5,6] del l1[1::2] print(l1)
2.倒叙删除
l1 = [1,2,3,4,5,6] for i in range(len(l1)-1,-1,-2): l1.pop(i) print(l1) >>>[1,3,5] #不能用如下代码; l1 = [1,2,3,4,5,6] for i in range(1,len(l1),2): l1.pop(-i)
3.思惟转换
l1 = [1,2,3,4,5,6] l2 = [] for i in range(0,len(l1),2): l2.append(l1[i]) l1 = l2 print(l1)
b=sorted(a,reverse=True) 函数按照长短、大小、英文字母的顺序给列表中的元素进行排序,但不会改变列表自己
列表是有序的,能够用enumerate()函数在索引的时候获得每一个元素的具体位置:
l1 = ['a','b','c'] for num,int in enumerate(l1): print(num,int) >>>0 a 1 b 2 c
列表的嵌套
列表推导式:用一行代码构建一个比较复杂有规律的列表。
l1 = [i for i in range(10)] #可将range换为可迭代对象。
列表推导式可分为两类。
- 循环模式:需遍历每个元素。[变量(加工后的变量) for 变量 in iterable]
#例1:将10之内全部整数的平方写入列表: l1 = [i*i for i in range(11)] print(l1) #例2:100之内的全部奇数写入列表: l1 = [i for i in range(1,100,2)] print(l1) #例3:从python1到python10写入列表: l1 = [f'python{i}' for i in range(1,11)] print(l1)
- 筛选模式:[变量(加工后的变量) for 变量 in iterable if 条件]
#例1:将10之内可以被2整除的数写入列表 l1 = [i for i in range(11) if i%2==0] print(l1) #例2:过滤列表l1中小于3的字符串,将剩下的转换成大写。l1 = ['nonl','globals','as','in'] l1 = ['nonl','globals','as','in'] l2 = [i.upper() for i in l1 if len(i)>=3] print(l2) #例3:将num列表中含有两个0的字符串生成一个新列表。num = [['021','001','201'],['100','012','010']] l1 = [j for i in num for j in i if j.count('0') == 2] print(l1)
缺点:
- 只能构建计较复杂而且有规律的列表;
- 超过三层循环才能构建成功的,不建议使用列表推导式;
- 没法找查错误(debug模式)
tuple
为只读列表。可存大量的数据,能够索引,切片(按步长),不可更改,但元祖中列表里的元素能够按照列表更改,示例: (1, True, [1, 2, 3])。
特殊性:元祖中只有一个元素,而且没有’,‘,则它不是元祖,它与括号中的数据类型一致
print(type((1,2))) #<class 'tuple'> print(type((1))) #<class 'int'> print(type((1,))) # <class 'tuple'>
count() 计数
index() 找索引
元祖的拆包:分别赋值,必须一 一对应。(列表也能够拆包,但通常不用)
a,b=(1,2) print(a,b) #1 2 #与*(聚合)使用: a,b,*c = (1,2,3,4,5,6,7,) print(a,b,c) #1 2 [3, 4, 5, 6, 7] a,*b,c = (1,2,3,4,5,6,7,) print(a,b,c) #1 [2, 3, 4, 5, 6] 7 a,*b,c = [1,2,3,4,5,6,7,] print(a,b,c) #1 [2, 3, 4, 5, 6] 7 a,*b,c=range(10) print(a,b,c) #0 [1, 2, 3, 4, 5, 6, 7, 8] 9
字典
键必须是不可变的数据类型,最经常使用的是str int,键是不能改变且没法修改,而值能够改变,可修改,能够是任何对象。键是不能重复的,而值能够重复。字典在3.5x版本以前(包括3.5)是无序的;字典在3.6x会按照初次创建字典的顺序排序的,学术上不认为是有序的。字典3.7x之后都是有序的。字典以空间换时间,查询速度很是快,内存消耗巨大。
字典的建立方式:
dic = dict((('i',1),('love',2),('you',3))) #用列表也能够dic = dict([('i',1),('love',2),('you',3)]),列表或元祖中的每一个元素是一个二元组就能够用dict()转换为字典。 print(dic) >>>{'i': 1, 'love': 2, 'you': 3} dic = dict(i=1,love=2,you=3) print(dic) >>>{'i': 1, 'love': 2, 'you': 3} dic = dict({'i': 1, 'love': 2, 'you': 3}) print(dic) >>>{'i': 1, 'love': 2, 'you': 3} #字典推导式 dic = {i:i+1 for i in range(3)}
增,添加多个元素的方法:
update():有键则改,无键则增长。
setdefault():有则不变,无则增长
fromkeys():第一个参数必须为可迭代对象,可迭代的对象共用第二个参数(id相同)。
dic = {} dic['age'] = '18' dic.setdefault('able') print(dic) #{'able':None} dic.setdefault('hobby':python) dic = dict.fromkeys('abc',1) print(dic) #{'a': 1, 'b': 1, 'c': 1} dic = dict.fromkeys([1,2,3],[]) print(dic) #{1: [], 2: [], 3: []} dic[1].append('a') print(dic) #{1: ['a'], 2: ['a'], 3: ['a']}
删:
popitem() 3.5版本以前,随机删除,3.6版本以后,删除最后一个,有返回值。
pop(),按照键删除,有返回值,返回的为字典的值,若是没有要删除的键,则会报错,但能够设置第二个两个参数,不管字典中是否有此键,都不会报错,如有此键则返回值为此键的值,若无此键则,返回设置的参数。
del,若无键会报错,不推荐使用
clear 清空
dic = {} print(dic.pop('hobby','没有此键值对')) #没有此键值对。 del dic['age'] #报错 dic.claer()
改
dic['name'] = 18
update() 有则覆盖,无则增长
#1.增长/改键值对 dic0 = {1:'i'} dic1 = {3: 'c'} dic0.update(a='love') #a位置不能是int类型 dic0.update(dic)
查
dic = {'name':'山就在那儿','hobby_list':['book','python']} print(dic['hobby_list']) #若没有此键则会报错,不建议用 l1 = dic.get('hobby_list') #若没有键则会返回None,能够定义第二个参数,第二个参数即为返回值 #keys() print(dic.keys()) #会返回一个dict_keys类型,包含字典中全部的键,和列表类似,但不能索引,转化成列表后可遍历 >>>dict_keys(['name', 'hobby_list']) #values() print(dic.values()) #会返回一个dict_values类型,包含字典中全部的值,和列表类似,但不能索引,可转化成列表后可遍历 >>>dict_values(['山就在那儿', ['book', 'python']]) #items() for k,v in dic.items(): #元祖的拆包 for i in dic.items() print(i) 打印的结果数据为元祖 #小题试作:将字典dic中的以‘k’开头的键值对删除,(循环一个字典时,若果改变字典的大小则或报错。) dic = {'k1':'a','k2':'b','k3':'c','a':'d'} l1 = [] for key in dic: if key.startswith('k'): l1.append(key) for i in l1: dic.pop(i) #改进 for key in list(dic.keys()): #将其转换为一个列表,若不加list则会报错。 if 'k' in key: dic.pop(key)
字典的嵌套
字典推导式
l1 = ['1','2','3'] l2 = ['一','二','三'] dic = {l1[i]:l2[i] for i in range(len(l1))}
set
集合:容器型数据类型,要求它里面的元素是不可变的数据(可哈希),但它自己是可变的数据类型(不可哈希)。集合是无序的。以{}存放数据。
做用:列表的去重;关系的测试(交集,并集…)
集合的建立:
set = {1,2,'a'} #空集合的表示: set1 = set() #set1 = {}表示空字典
增:add()、update():迭代增长,有重复的则去重
set1 = {1,2} set1.add('a') set1.update('asdfdsa') print(set1) >>>{'a', 1, 2, 'f', 's', 'd'}
删:remove()(按照元素删除,pop()随机删除,clear()清空集合,del 删除集合,discard()有则删除,无则pass,不报错。
改:先删除再增长
交集。(&或者intersection) 集合共同有的元素
set1 = {1,2,3} set2 = {2,3,4} print(set1 & set2) #or print(set1.intersection)
并集。(|或者union)集合全部的元素
set1 = {1,2} set2 = {2,3} print(set1 | set2) #or print(set1.union(set2))
差集 ( - 或者difference) ,前一集合独有的元素
set1 = {1,2,3,4,5} set2 = {2,4,6} print(set1 - set2) #or print(set1.difference(set2))
反交集。(^ 或者symmetric_difference)每一个集合独有的元素
set1 = {1,2,3,4,5} set2 = {3,4,5,6,7} print(set1 ^ set2) #or print(set1.symmetric_difference(set2)) >>>{1,2,6,7}
子集与超集
set1 = {1,2} set2 = {1,2,3} print(set1 < set2) #or print(set1.issubset(set2)) #or print(set2.issuperset(set1)) >>>True #set1是set2的子集 print(set2 > set1) >>>True #set2是set1的超集
frozenset()让集合变为不可变类型
s = frozenset('qweasd') print(s,type(s)) >>>frozenset({'q', 'e', 'w', 's', 'a', 'd'}) <class 'frozenset'>
S集合推导式
set1 = {i for i in range(10)}
正则表达式
- 检测一个输入的字符串是否合法。(web开发项目 表单验证)
- 从一个大文件中找到全部符合规则的字符串。(日志分析、爬虫)
在正则表达式中表示匹配内容的符号是正则中的元字符,匹配次数的是量词正则都是从左至右依次匹配。
字符组:[]
,描述的是一个位置上出现的全部的可能性。一个字符组只能匹配一个字符。根据ASCII进行匹配。[0-9] 、[a-z]、[A-Z](ASCII码值:Z为91,a为97)。能够从小到大匹配,但不能从大到小匹配,如:[Z-a]。
[A-Z]
:a-Z中间有一些特殊字符,所以不用此方法匹配所有的大小写字母。[a-zA-Z]
:匹配所有的大小写字母。[0-9a-zA-Z]
\d
:digit,表示匹配任意的一个数字,同[0-9]
,或[\d]
。
\w
:word(标识符,变量名),表示匹配任意的一个数字、字母、下划线,同[0-9a-zA-Z_]
。
\s
:匹配全部的一个空白符(空格、Tab、Enter),同(‘ ’、‘\t’、‘\n’)
\t
:匹配Tab。
\n
:匹配Enter,即回车。
\W
:匹配任意一个的非数字、字母、下划线。
\D
:匹配任意的一个非数字。
\S
:匹配一个非空白符。
[\d\D]
:匹配全部,同[\w\W]、[\s\S]。
.
:正常状况匹配除换行符以外的一切字符。但在re模块中可用参数更改成匹配全部。
非字符组:[^]
[^\d]
:匹配全部的非数字。
^
:表示匹配一个字符串的开始。
$
:表示匹配一个字符串的结尾。^于&一般用于约束。
a表达式|b表达式
:能匹配a或b表达式里的内容,若是a匹配成功了就不会匹配b,全部若是两个规则有重叠的部分老是将表达式长的放在左面。
()
:分组,约束元字符的做用范围,常常用于|。
\
:转义字符,本来有特殊意义的字符要表达它自己的意义时,须要转移;有一些特殊意义的内容,放在字符组中,会取消它的特殊意义,如[. () * + ?]
只能表示它特殊的意义。-
放在两值之间表示两值的范围,容不须要表示范围,须要加\
,-
若放在字符组的开头或结尾就只表示-
。
\b
:匹配单词的边界。找以ing结尾的单词ing\b
。
量词:{n}:表示匹配n次。
{n,}
:表示匹配至少n次。
{n,m}
:表示至少匹配n次,至多匹配m次。
?
:表示匹配0次或1次,同{0,1}
+
:表示匹配一次或屡次,同{1,}
*
:表示匹配0次或屡次,同{0,}
例子:匹配整数\d+
,匹配小数\d+\.\d+
,匹配一个整数或小数\d+\.?+\d*
但此时会出现问题,如12.
也会被匹配上。这时能够用分组:\d(\.\d+)?
匹配一个手机号码:^1[3-9]\d{9}$
贪婪匹配:会在量词范围容许的状况下尽可能向多的方向匹配。根据回溯算法,从左至右依次按照规则匹配,若规则不知足最后的条件,就会回溯,形成贪婪模式。.*x
表示匹配任意字符,任意屡次,遇到最后一个x才停下来。
惰性匹配:非贪婪匹配,在量词后加上?
,会在量词范围容许的状况下尽可能少的匹配。.*?x
表示匹配任意字符,任意屡次,一旦遇到x就停下来。
匹配一个18位或者15位的身份证号:
^[1-9]\d{16}[\dx]$|^[1-9]\d{14}$
或
^([1-9]\d{16}[\dx]|[1-9]\d{14})$
或
^[1-9]\d{14}(\d{2}[\dx])?$
代码块、缓存机制
id、is、==
-
id: 数据的内存地址具备惟一性,若id 相同则为同一个数据。id():获取数据的内存地址(随机的地址:内存临时加载,存储数据,当程序运行结束后,内存地址即被丢弃)
-
is 判断id是否相同,==:判断值是否相同。id相同,值必定相同,值相同,id不必定相同。
l1 = [1,2,3] l2 = [1,2,3] print(l1 == l2) #True #比较的是两边的值是否相等。 l1 = [1,2,3] l2 = [1,2,3] print(l1 is l2) #False 判断的是(id)是否相同。 s1 = 'iam' s2 = 'iam' print(s1 is s2) #True 与同一代码块下的缓存机制有关 l1 = [1,2,3] l2 = l1 print(l1 is l2) #True
代码:python的程序是由代码块构造的。块是一个python程序的脚本,它是做为一个单元执行的。一个模块,一个函数,一个类,一个文件等都是代码块。而做为互交命令方式输入的每一个命令都是一个代码块。
代码块的两个缓存机制:若是在同一代码块下,则采用同一代码块下的换缓存机制。若是是不一样代码块,则采用小数据池的驻留机制。优势:须要值相同的字符串,整数的时候,直接拿来用,避免频繁的建立和销毁,提高效率,节约内存
同一个代码块的缓存机制:Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,若是存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,它会将初始化的这个变量与值存储在一个字典中,在遇到新的变量时,会先在字典中查询记录,若是有一样的记录那么它会重复使用这个字典中的以前的这个值,即:id相同。
-
适用对象:
int:任何数字在同一代码块下都会复用。
str:几乎全部的字符串都会符合缓存机制
bool:True和False在字典中会以1,0方式存在,而且复用。s1 = 'iam' s2 = 'iam' print(s1 is s2) >>>True
在不一样一个代码块内的缓存机制:小数据池,也称为小整数缓存机制,或者称为驻留机制等等。Python自动将-5~256的整数进行了缓存,将必定规则的字符串在字符串驻留池中建立一份。不管是缓存仍是字符串驻留池,都是python作的一个优化,就是将~5-256的整数,和必定规则的字符串,放在一个‘池’(容器,或者字典)中,不管程序中哪些变量指向这些范围内的整数或者字符串,那么它直接在这个‘池’中引用,并不会从新建立对象,而是使用已经建立好的缓存对象。言外之意,就是内存中之建立一个。
-
适用对象:
int(float):对于整数,小数据池的范围是-5~256 ,若是多个变量都是指向同一个(在这个范围内的)数字,他们在内存中指向的都是一个内存地址。
str:字符串的长度只含有大小写字母,数字,下划线时,才会默认驻留。
bool值:True、False,不管建立多少个变量指向True,False,那么它在内存中只存在一个。#经过交互方式中执行下面代码,这是不一样代码块下,则采用小数据池的驻留机制。 >>> i1 = 1000 >>> i2 = 1000 >>> print(i1 is i2) False # 不一样代码块下的小数据池驻留机制 数字的范围只是-5~256. #4.指定驻留 >>>from sys import intern >>>a = intern('hello!@'*20) >>>b = intern('hello!@'*20) >>>print(a is b) True #指定驻留是你能够指定任意的字符串加入到小数据池中,让其只在内存中建立一个对象,多个变量都是指向这一个字 # 虽然在同一个文件中,可是函数自己就是代码块,因此这是在两个不一样的代码块下,知足小数据池(驻存机制),则指向两个不一样的地址。
def func():
i1 = 1000
print(id(i1)) # 2288555806672
def func2():
i1 = 1000
print(id(i1)) # 2288557317392
func()
func2()
```
深浅copy
浅copy:嵌套的可变的数据类型是同一个。深copy:嵌套的可变的数据类型不是同一个。
浅copy,列表是一个一个的槽位,它储存的是对象的内存地址。浅拷贝仍然使用原来的对象的内存地址。对储存的可变对象能够进行更改;若改变不可变类型,则改变的不是不可变类型自己,而是变量的指向关系,切片是浅copy。
l1 = [1,2] l2 = l1 l1.append(3) print(l2) >>>[1,2,3] #l1,l2两变量指向同一个id(数据) #浅copy l3 = [1,2,['a']] l4 = l3.copy() l3.append(3) print(l3) >>>[1,2,['a'],3] print(l4) >>>[1,2,['a']] l3[-2].append(4) #or l4[-1].append(4) print(l3) >>>[1, 2, ['a', 4], 3] print(l4) >>>[1,2,['a',4]] #l4与l3列表中的数据id是相同的,但l4与l3列表id不相同,即l3中的每一个元素与l4中的每一个元素使用的是相同的一个id,但l4与l3用的不是同一个id。
深copy,需导入模块copy。深拷贝会给对象建立一个新的内存地址,python对深copy作了一个优化,不可变数据类型对象的内存地址沿用同一个,只为可变数据类型对象再从新建立内存地址。
import copy l3 = [1,2,['a']] l4 = copy.deepcopy(l3) l3[-1].append(3) print(l3) >>>[1,2,['a',3]] print(l4) >>>[1,2,['a']]
文件的操做
open() 内置函数,open底层调用的是操做系统的接口。有三个参数:1. 文件路径 (文件夹路径+文件名+文件类型) 2. 编码方式:encoding,参数不写会以操做系统默认的编码本打开,windows默认编码:gbk(windows10是utf-8,Linux:utf-8,mac:utf-8)。3.模式:mode,须要有两个方向给予指定:打开文本的模式、打开文件的方向,默认不写第一个方向则以读(r)的方式打开,默认不写第二个则以文本模式打开。
文件的方向:t(text,文本模式)、b(binary,字节模式)。
文件的模式:a(append,追加)、w(write,写)、r(read,读)
文件句柄:变量,通常在文件操做是设置的约定俗成的变量,也有写做为f1,fh,file_handler,f_h等,也被称为文件句柄。经过对文件进行的任何操做都要做用于文件句柄(如fl.raed())。
常见报错缘由:
-
UnicodeDecodeError:文件储存时与文件打开时编码本运用不一致。
-
路径分隔符产生问题:\ (反斜杠) 有转义符的意思。解决方法:在文件路径前加r,让转义符失效,也可以使用两次转义:
\\
。
文件的读:
rt、rb、r+、r+b等。
-
read() 若括号中无参数则一次所有读出,若写参数(数字)则能够按照字符(从1开始)读取,文件中的换行符算做一个字符。
-
readline() 若括号中无参数则读一行,若写参数(数字)则能够按照字符(从1开始)读取字符(同read),文件中的换行符算做一个字符。注意,文本中有换行符,而print()函数也默认换行。
-
readlines() 若括号中无参数读取全部行,返回列表,列表的每一个元素为源文件的每一行,若写参数(数字)则能够按照每一行读取。
-
循环读取,文件句柄可遍历(文件句柄是迭代器,每次for循环时都只读取文件一行,节省内存,而read,readlines等是一次读取至内存中,若果文件过大,则会出现问题)。
f = open(r'd:\python.txt',encoding='utf-8') for line in f: print(line) f.close() #每次操做文件后必定要关闭。
-
rb:操做的是非文本的文件,好比:图片,视频,音频等。rb模式不用encoding参数。
fl = open(r'd:\雪景.jpg',mode='rb') #雪景.jpg是张照片
以b方式打开,字节没有行的概念。若文件过大最好设置每次读取多少字节
-
r+ 读写功能(读并追加),必须先读或将指针调制文档末尾才能追加不然按照字节覆盖,极易出现乱码问题或报错。
文件的写:
- wt、wb、w+、w+b等。
- w,wb: 若已有相同的文件则会先清空原有文件的内容再写入 ,若无则建立。清空:打开文件后会先清空原文件再写入。
文件的追加:
- at、ab、a+、a+b等。
- a:若无文件则会建立文件。如有则直接在原文件后追加
指针:
- 文件的读取都有指针定位,文件中的指针起始位置在文件最前面。
- tell():读取指针的位子,以****字节**为单位(utf-8编码:一个中文三个字节,一个字母1个字节)
seek():调整光标的位置,以字节为单位
flush():强制刷新(保存),通常在写文件时使用,在写后通常要对文件句柄使用flush方法,以避免保存失败。
打开文件的另外一种方式
-
with open() as f1:
优势:不用手动关闭文件句柄,会在必定时间内关闭;一个with能够操做多个文件。#打开多个文件: with open(r'd:\text.txt',encoding='utf-8',mode='a') as f1,open(r'd:\python.txt',encoding='utf-8',mode='a') as f2:
各大操做文件的软件(word、笔记本等等)底层都以如下基本方式操做文件:
- 以读的模式打开原文件
- 以写的模式建立一个新文件
- 将原文件的内容读出来修改为新的内容,写入新文件
- 将原文件删除
- 将新文件重命名
小题试练:将d盘下的python.txt文件中的小写o全变为大写。
import os #引入os模块 #1.以读的模式打开原文件 #2.以写的模式建立一个新文件 with open(r'd:\python.txt',encoding='utf-8') as f1,\ open(r'd:\python.bak',encoding='utf-8',mode='w') as f2: #.bak是一种备份文件类型 #3.将原文件的内容读出来修改为新的内容,写入新文件 for old_line in f1: new_line = old_line.replace('o','O') f2.write(new_line) #4.将原文件删除 os.remove('d:\python.txt') #5.将新文件重命名 os.rename('d:\python.bak','d:\python.txt')
函数
return: 在函数中遇到return直接结束函数;能够给函数外部返回一个返回值,将数据返回给函数的执行者,调用者。返回值可被print打印出,若无返回值,print会打印出None。return可返回多个值,会以元祖的形式将多个元素返回给函数的执行者。(元祖能够进行拆包)
参数:实参,函数的执行时传入的参数。形参,函数的定义时接受的参数
实参角度:
-
位置参数:按照实参位置参数与形参的对应顺序(从左到右)依次传入。
-
关键字参数
-
混合传参
形参角度:
- 位置参数
- 默认参数(默认值参数)
- 万能参数:*args 接受全部的位置参数 ; **kargs 接受全部的关键字参数。
- 仅限关键字参数(3.4版本之后):只能接受关键字参数。若设置此参数必须给此参数传入值,不然会报错。此参数只能在*args与**kargs之间。
形参的顺序:调用函数时,会自动从左至右传入参数。形参的顺序以下:1.位置参数 2.*args 3.默认参数 3. 仅限关键字参数 4.**kargs。仅限关键字参数与默认参数可互换。
def func(a,b,*args,c='',d,**kargs): pass #a,b:位置参数 d:仅限关键字参数,只能有关键字参数为其传参。
函数不能改变全局不可变的变量,可变数据仍然可改变。
l1 = [1,2] def a(l1): l1.pop(1) a(l1) print(l1)
匿名函数(用lambda构建):结构比较简单的函数。形式:lambda 参数 : 返回值
def func(a,b): return a+b #构建匿名函数: func1 = lambda a,b:a+b print(func1(1,2))
lambda 参数 : 返回值:lambda后直接加形参,形参加多少均可以,但通常只用位置参数,参数之间须要用”,“隔开。
#例1:接受一个可切片的数据,以元祖形式返回索引位0与2的对应元素 func = lambda a:(a[0],a[2]) #例2:接收两个int参数,将较大的数据返回。 func = lambda a,b:a if a>b else b
命称空间
在python解释器开始执行以后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 可是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间,函数中的变量只能在函数内部使用。随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空。咱们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
全局名称空间:代码在运行伊始,建立的存储'变量名与值的关系'的空间叫作全局命名空间。即 在py文件中, 除函数外声明的变量都属于全局命名空间。程序不结束,全局名称空间不会消失。
局部名称空间:在函数的运行中开辟的临时的空间叫作局部命名空间也叫作临时名称空间,临时存放函数中的变量与值的关系。即在函数中声明的变量会放在局部命名空间。函数结束时局部命名空间就会消失。
内置名称空间:内置名称空间存放的就是一些内置函数等拿来即用的特殊的变量:input,print,list等。
加载顺序:这个三个空间在内存中建立的前后顺序,他们不能同时建立,在启动python解释器以后,即便没有建立任何的变量或者函数,仍是会有一些函数直接能够用,所以在启动Python解释器的时候,一些函数就已经导入到内存当中供咱们使用,因此是先加载内置名称空间,而后就开始从文件的最上面向下一行一行执行,此时若是遇到了初始化变量,就会建立全局名称空间,将这些对应关系存放进去,而后遇到了函数执行时,在内存中临时开辟一个空间,加载函数中的一些变量等等。因此这三个空间的加载顺序为:内置命名空间(程序运行伊始加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载。
取值顺序:若是在全局名称空间引用一个变量,会先从全局名称空间引用,全局名称空间若是没有,才会向内置名称空间引用。 若是在局部名称空间引用一个变量,先从局部名称空间引用,局部名称空间若是没有,才会向全局名称空间引用,全局名称空间再没有,就会向内置名称空间引用。
因此取值顺序知足的就近原则,从小范围到大范围一层一层的逐步引用且单向不可逆,即LEGB原则。(L:lcoal E:eclose G:global B:builtin)
做用域:做用域就是做用范围, 按照生效范围来看分为全局做用域和局部做用域
- 全局做用域: 包含内置命名空间和全局命名空间. 在整个文件的任何位置均可以使用(遵循从上到下逐⾏执行)。全局做用域: 全局命称空间 + 内置命称空间
- 局部做用域: 在函数内部可使用。2. 局部做⽤域: 局部命称空间,局部做用域能够引用全局做用域的变量但不能改变全局变量(当python解释器读取到局部做用域时,若发现有对一个变量进行修改的操做,解释器会认为你在局部已经定义过这个局部变量了,因而就在局部找这个局部变量,若没有就会报错,没法改变全局变量),全局做用域不可义引用局部做用域的变量。
内置函数: globals() local()
-
globals(): 以字典的形式返回全局做用域(内置命称空间以及全局命称空间的全部内容)全部的变量对应关系。
-
locals(): 以字典的形式返回当前做用域的变量全部的对应关系。
-
函数的嵌套(高阶函数):
关键点:只要碰见了函数名+()就是函数的调用. 若是没有就不是函数的调用。请说出下面代码的执行顺序:#例1: def func1(): print('in func1') print(3) def func2(): print('in func2') print(4) func1() print(1) func2() print(2) # 例2: def func1(): print('in func1') print(3) def func2(): print('in func2') func1() print(4) print(1) func2() print(2) # 例3: def func2(): print('1in func2') def func3(): print('in func3') print('2in func2') func3() print('3in func2') print(3) func2() print(5)
默认参数的陷阱(只针对于默认参数是可变的数据类型):若是默认参数使用的是可变类型数据,那么不管调用多少次这个默认参数,都是同一个(id相同)。默认参数的可变数据类型既不在全局也再也不局部,定义后不会消失。
def func(num,nums=[]): nums.append(num) return nums ret1 = func(1) print(ret1) #[1] ret2 = func(2) print(ret2) #[1,2] 将第一次的数据也包含了。 #例: def func(a,list=[]): list.append(a) return list ret1 = func(10,) print(ret1) #[10] print(func(20,[])) #[20] #从新为列表传入参数 print(func(100)) #[10,100] print(ret1) #[10,100]
局部做用域的陷阱:在函数中,若是定义一个变量,可是在定义变量以前改变这个变量,即便全局变量有此引用的变量,仍然会报错。
#例1: count = 1 def func(): count += 1 print(count) func() IndentationError: unindent does not match any outer indentation level #例2: count = 1 def func(): print(count) func() #1 #例3: count = 1 def func(): print(count) count = 1 func() UnboundLocalError: local variable 'count' referenced before assignment
global:在局部做用域里声明一个全局变量。
#1. def func(): global num num = 1 print(num) #会报错。 #2. num = 0 def func(): global num num = 1 func() print(num) #1
nonlocal:不可以操做全局变量;主要用于内层函数对外层函数的局部变量进行修改。
def func1(): count = 1 def inner(): nonlocal count count+=1 inner()
函数名的运用
- 函数名指向的是函数的内存地址
函数名+()
就能够执行函数 - 函数名能够做为容器类数据类型的元素
- 函数名能够做为函数的参数
- 函数名能够做为函数的返回值。
迭代器
可迭代对象(iterable):
对象:python中一切皆对象。 可迭代:能够进行循环更新的一个值。以专业角度来讲,内部含有__iter__
方法的对象即为可迭代对象。如:str、list、tuple、dict、set、range等。
获取对象的全部方法而且以字符串的形式表现:dir()
s1 = 'qwer' print(dir(s1))
判断一个对象是不是可迭代对象:
s1 = 'qwer' print('__iter__' in dir(s1)) #True
可迭代对象的优势:
- 存储的数据可以直接显示,比较直观。
- 拥有的方法比较多,操做起来方便。
可迭代对象的缺点:
- 占内存。
- 不能直接经过for循环(不能直接取值),python内部自动将其转换为迭代器而后再进行for循环(用next()方法取值)。
迭代器:
迭代器的定义:内部含__iter__
和__next__
方法的对象就是迭代器,可判断是否为可迭代器。文件句柄是常见的迭代器。
可迭代对象能够转换为迭代器iter()
或.__iter__()
:
s1 = 'qwert' obj = iter(s1) #或者: s1.__iter__() print(obj) #会返回一个迭代器的内存地址
对迭代器进行取值next()
或.__next__()
:
迭代器优势:
- 节省内存,迭代器在内存中至关于只占一个数据的空间,由于每次取值上一条数据都会在内存释放。迭代器具备惰性机制,next一次,只取一个值,毫不多取。
迭代器的缺点:
- 不能直观的查看里面的数据。
- 只能一直向下取值。
- 速度慢。
可迭代对象与迭代器的对比:
- 可迭代对象是的操做方法比较多,比较直观,储存数据相对少(几百万个数据,8G内存是能够承受的)的一个数据集。当侧重于对于数据能够灵活处理,而且内存空间足够,可将数据设置为一个可迭代对象。
- 迭代器是很是节省内存,能够记录取值位置,能够经过循环加next方法取值,可是不直观,操做方法比较单一的一个数据集。当数据量过大,可选择将数据设置为一个迭代器。
用while循环模拟for循环对可迭代对象进行取值:
l1 = [1,2,3,4,5,6,7,8] obj = iter(l1) while 1: try: #try:异常处理 print(next(obj)) except StopIteration: break
生成器
生成器:python社区把生成器与迭代器当作同一种,生成器的本质就是迭代器。惟一的区别是:生成器是咱们本身用python代码构建的数据结构,迭代器都是python提供的,或者转化的。
获取生成器的方法:
- 生成器函数
- 生成器表达式
- python内部提供的。
生成器函数获取生成器,yield:
def func(): print(1) print(3) yield 5 print(func) #<function func at 0x000001A3CCA04438> 仍然是一个函数 ret = func() print(ret) #<generator object func at 0x000002471A631D48> #generator object#生成器对象 #一个next对一个yield的返回值,若是再次调用yield就会接着上次的next. def func(): for i in range(1000000): yield i ret = func() for i in range(5): print(next(ret)) for i in range(10): print(next(ret)) #0, 2,3,4,5,6,7,8,9,10,11,12,13,14
yield与return
return:一个函数中只能存在一个return结束函数的调用,而且给函数的执行者返回值。
yield:只要函数中有yield那么它就是生成器函数,生成器函数中能够存在多个yield,一个next对一个yield的返回值,yield不会结束函数的调用,但return会结束函数的调用。
yield from(3.4版本之后),将数据变成一个迭代器返回,生成器函数能够直接用for循环
def func(): l1 = [1,2,3] yield from l1 #将这个列表变成了一个迭代器返回 for i in func(): print(i) #1 2 3
生成器表达式,生成器表达式:与列表推导式的写法几乎同样,生成器也有循环模式和筛选模式,只是将[]变为()。但比列表推导式更节省空间。
l1 = (i for i in range(10)) print(l1) #<generator object <genexpr> at 0x000001BB028F8CC8> print(next(l1)) #0 for i in l1: #可直接用for循环,由于for循环自己就是将可迭代对象变为迭代器再循环。 print(i)
list能够将生成器中的全部元素添加到列表中
def func(*args): for i in args: for j in i: yield i print(list(func('asdf',(1,2,3)))) #简化上述函数: def func(*args): for i in args: yield from i #优化了内层循环,提升了运行效率。
递归函数
递归报错:RecursionError
官方文档递归最大深度为1000层,为了节省内存空间,不让用户无限开辟内存空间。但实际上不是1000层。
递归的实现效率比不用递归的实现效率低。
count = 0 def func(): global count count += 1 print(count) func() print('***') #不会被执行。 func()
循环和递归的关系:递归比循环更消耗内存。
递归的最大深度能够本身设置:
import sys sys.setrecursionlimit(100000) count = 0 def func(): global count count += 1 print(count) func() func()
但并不会无限制按照设置的参数的开辟内存空间,达到必定限度后会自行中止,而这个限度与电脑有关。
设置条件,让递归函数停下来。
def main(n): print('进入第%d层梦境'%n) if n == 3: print('到达潜意识区,原来我最爱的人是你!开始醒来') else: main(n+1) print('从第%d层梦境醒来'%n) main(1)
并非函数中有return
,return
的结果就必定可以在调用函数的外层接受到
def func(count): count+=1 if count == 5:return 5 func(count) print(func(1)) #None def func(count): count+=1 if count == 5:return 5 return func(count) #调用后用return print(func(1))
递:一直往深处走,归:从深处返回。
例题:
1.计算阶乘。
def func(n): return n*func(n-1) if n>1 else 1 print(func())
2.os模块,查看一个文件夹下的全部文件,不能用walk。
import os def show_file(path): name_list = os.listdir(path) print(name_list) for name in name_list: abs_path = os.path.join(path,name) if os.path.isfile(abs_path): print(abs_path) elif os.path.isdir(abs_path): show_file(abs_path) show_file('D:\WorkSpace\Python')
3.os模块,计算一个文件加下全部文件的大小。
import os def dir_size(path): size = 0 name_lst = os.listdir(path) for name in name_lst: abs_path = os.path.join(path, name) if os.path.isdir(abs_path): ret = dir_size(abs_path) size += ret elif os.path.isfile(abs_path): size+=os.path.getsize(abs_path) return size print(dir_size('D:\WorkSpace\Python')/(1024*1024))
3.计算斐波那契数列,找第100个数。
def func(n): x = n-1 return func(n-1) +func(n-2) if x>1 else 1 print(func(100)) #很是浪费时间,在递归时尽可能避免屡次调用函数。 def fib(n,a=1,b=1): if n-1<1: return b else: a,b=b,a+b return fib(n-1,a,b) print(fib(100)) #采用while循环 def fib(n): a,b = 1,1 while n>2: a,b = b,a+b n -= 1 return b print(fib(100)) #采用生成器: def fib(): a = 1 yield a b = 1 yield b while True: a,b = b,a+b yield b import time for i in fib(): print(i) time.sleep(0.01)
4.三级菜单。
menu = { '北京': { '海淀': { '五道口': { 'soho': {}, '网易': {}, 'google': {} }, '中关村': { '爱奇艺': {}, '汽车之家': {}, 'youku': {}, }, '上地': { '百度': {}, }, }, '昌平': { '沙河': { '北航': {}, }, '天通苑': {}, '回龙观': {}, }, '朝阳': {}, '东城': {}, }, '上海': { '闵行': { "人民广场": { '炸鸡店': {} } }, '闸北': { '火车战': { '携程': {} } }, '浦东': {}, }, '山东': {}, } def threeLM(dic): while True: for k in dic:print(k) key = input('input>>').strip() if key == 'b' or key == 'q':return key elif key in dic.keys() and dic[key]: ret = threeLM(dic[key]) if ret == 'q': return 'q' threeLM(menu)
内置函数
python提供了68个内置函数:abs() enumerate() filter() max() min() open() range() print() len() list() dict() str() float() reversed() set() sum() tuple() type() zip() dir() classmethod() delattr() getattr() issubclass() isinstance() object() property() setattr() staticmethod() super() all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() id() input() int() locals() next() oct() ord() pow() repr() round()
eval():剥去字符串的外衣(引号),运算里面的代码,有返回值。工做时最好不用,容易中病毒。
s1 = '1+1' print(s1) #1+1 print(eval(s1),type(eval(s1))) #2 <class 'int'>
exec():与eval()几乎同样,可是它是处理代码流的。工做时最好不用,容易中病毒。
msg = """ for i in range(5): print(i)""" exec(msg) #0,1,2,3,4
hash:获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值。哈希值:加密算法之间须要哈希值,与哈希算法有关。
print(hash('12'))
help():打印/获取一个对象的使用方法。
print(help(str)) print(help(str.upper))
callable():判断一个对象是否可调用,真为True,假为False。
l1 = [1,2] def func(): pass print(callable(l1)) #False print(callable(func)) #True
int():将字符串类型转换为int类型;取整(舍尾法)
float():将int和str转换为float。
list():将一个可迭代对象转换成列表
tuple():将一个可迭代对象转换成元组
dict():经过相应的方式建立字典。
abs():返回绝对值
sum():求和
reversed():将一个序列翻转,返回翻转序列的迭代器。可用于字符串。与列表的方法l1 .reverse()
区分.
complex:建立一个值为real+imag*j的复数;转换一个str或int为复数,若是第一个参数为str则不须要传递第二个参数。(复数:complex)
print(complex('1')) #(1+0j)
bin:将十进制数转换为二进制字符串并返回。
oct:将十进制数转换为八进制字符串并返回。
hex:将十进制数转换为十六进制字符串并返回。
divmod:计算除数与被除数的结果,返回一个包含商和余数的元祖(a//b,a%b)
round:保留浮点数的位数,默认保留整数。
pow:求x**y的次幂,并能够对所求结果对第三个参数取余
print(pow(2,2)) #2**2 4 print(pow(2,2,3)) #(2**2)%3 1
bytes:用于不一样编码之间的转换。
s1 = '你好' bs1 = s1.encode('utf-8') print(bs1) #b'\xe4\xbd\xa0\xe5\xa5\xbd' s2 = bs1.decode('utf-8') print(s1) #你好 s3 = '你好' bs2 = bytes(s3,encoding='utf-8') print(bs2) #b'\xe4\xbd\xa0\xe5\xa5\xbd' bs3 = str(bs2,encoding='utf-8') print(bs3) #你好
ord():输入字符找该字符编码的位置。(若是在ASCII码中就用ASCII码,不然用Unicode)
chr():输入位置数字找出其对应的字符。(若是在ASCII码中就用ASCII码,不然用Unicode)
repr():返回一个对象的string形式。(str带有引号的形式),在格式化输出时经常使用(%r)。
s1 = 'python' print('i love %r'%(s1)) #i love 'python'
print():源码分析:print(self, *args, sep=' ', end='\n', file=None,flush=False):
file: 默认是输出到屏幕,若是设置为文件句柄,输出到文件
sep: 打印多个值之间的分隔符,默认为空格
end: 每一次打印的结尾,默认为换行符
flush: 当即把内容输出到流文件,不做缓存
print(1,2,3) #1 2 3 print(1,2,3,sep='@') # 1@2@3 print(1,2,3,end='') #不换行
all():可迭代对象中,全为True才是True。
any():可迭代对象中,有一True即为True。
zip(): 拉链方法;函数用于将可迭代的对象做为参数,将对象中对应的元素打包成一个个元组,而后返回由这些元祖组成的内容,若是各个迭代器的元素个数不一致,则按照长度最短的返回。
lst1 = [1,2,3] lst2 = ['a','b','c','d'] lst3 = (11,12,13,14,15) for i in zip(lst1,lst2,lst3): print(i) #(1, 'a', 11) (2, 'b', 12) (3, 'c', 13)
min():求最小值,能够与函数结合(key:自动将可迭代对象中的每一个元素按照顺序传入key对应的函数中,而后以返回值比较大小,key=必定是函数名,不能加(),。min/max默认会按照字典的键去比较大小,但能够本身规定。
#以绝对值的方式取最小值 l1 = [1,2,-1,-5,3] def func(s): return abs(s) print(min(l1,key=func)) #1 #也能够直接使用匿名函数: print(min(l1,key=lambda s:abs(s))) #1 dic = {'a':3,'b':2,'c':1} min(dic) #a 默认以键排序,返回键 #以值比较: print(min(dic,key=lambda s:dic[s])) #c 以值排序,返回键(返回的是循环的元素,而不是经函数转换后比较的值。
max():求最大值,能够与函数结合,同min()。
sorted():排序函数;语法: sorted(iterable,key=None,reverse=False)。key: 排序规则(排序函数),返回列表。在sorted内部会将可迭代对象中的每个元素传递给这个函数的参数.根据函数运算的结果进行排序reverse: 是不是倒叙,True:倒叙;False:正序
lst = [1,3,2,5,4] lst2 = sorted(lst) print(lst) # 原列表不会改变 print(lst2) # 返回的新列表是通过排序的 lst3 = sorted(lst,reverse=True) print(lst3) # 倒叙 #字典使用sorted排序 dic = {1: 'a',3: 'c',2: 'b'} print(sorted(dic)) #[1,2,3] 字典排序返回的就是排序后的key #和函数组合使用 # 定义一个列表,而后根据一元素的长度排序 lst = ['1','111','11','1111'] # 计算字符串的长度 def func(s): return len(s) print(sorted(lst,key=func)) #['1','11','111','1111'] lst = [{'id': 1,'name': 'a','age': 18}, {'id': 2,'name': 'b','age': 17}, {'id': 3,'name': '3','age': 16},] # 按照年龄对学生信息进行排序 print(sorted(lst,key=lambda e: e['age']))
filter():筛选过滤,返回一个迭代器(可与列表推导式的筛选模式进行对比);语法: filter(function,iterable),function: 用来筛选的函数,在filter中会自动的把iterable中的元素传递给function,而后根据function返回的True或者False来判断是否保留此项数据
lst = [{'id':1,'name':'a','age':18}, {'id':2,'name':'b','age':17}, {'id':3,'name':'c','age':16},] ls = filter(lambda e:e['age'] > 16,lst) print(list(ls)) #[{'id': 1, 'name': 'alex', 'age': 18},{'id': 1, 'name': 'wusir', 'age': 17}]
map():映射函数,返回一个迭代器(可与列表推导式的循环模式对比);语法: map(function,iterable) 能够对可迭代对象中的每个元素进映射,分别取执行function。
#例1;计算列表中每一个元素的平方,返回新列表 lst = [1,2,3,4,5] print(map(lambda s:s*s,lst)) #<map object at 0x000002B2A4F04B88> print(list(map(lambda s:s*s,lst))) #例2;计算两个列表中相同位置的数据的和 lst1 = [1, 2, 3, 4, 5] lst2 = [2, 4, 6, 8, 10] print(list(map(lambda x, y: x+y, lst1, lst2)))
reduce():reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行,在Python2.x版本中recude是直接 import就能够的, Python3.x版本中须要从functools这个包中导入。
from functools import reduce def func(x,y): return x + y ret = reduce(func,[1,2,3]) print(ret) # 结果 6 #reduce的做用是先把列表中的前俩个元素取出计算出一个值而后临时保存着,接下来用这个临时保存的值和列表中第三个元素进行计算,求出一个新的值将最开始临时保存的值覆盖掉,而后在用这个新的临时值和列表中第四个元素计算.依次类推。注意:咱们放进去的可迭代对象没有更改 #如今有[1,2,3,4]想让列表中的数变成1234 l = reduce(lambda x,y:x*10+y,[1,2,3,4]) print(l)
闭包、装饰器
全局变量,数据不安全。使用局部变量,保证数据的安全。当内层函数对外层函数非全局变量的引用(使用)时,就会造成闭包。被引用的非全局变量也称做自由变量,这个自由变量会与内层函数产生一个绑定关系,令自由变量不会再内存中消失。闭包现象只能存在函数的嵌套中。
判断一个函数有没有自由变量:
def func1(): l1= [] def func2(num): l1.append(num) return l1 return func2 a = func1() # 函数名.__code__.co_freevars 查看函数的自由变量 print(a.__code__.co_freevars) # ('l1',) # 函数名.__code__.co_varnames 查看函数的局部变量 print(a.__code__.co_varnames) # ('num',) # 函数名.__closure__ 获取具体的自由变量对象,也就是cell对象。 print(a.__closure__) #(<cell at 0x000001EE151AC738: list object at 0x000001EE135851C8>,) # cell_contents 自由变量具体的值 print(a.__closure__[0].cell_contents) # []
装饰器:彻底遵循开放封闭原则,即在不改变原函数的代码以及调用方式的前提下,为其增长新的功能。(装饰器的本质是闭包)python提出了一个‘语法糖’的概念。在编写了装饰器后,须要将装饰器代码放在全部代码的前方。当要对装饰器函数调用时,在要装饰函数的前方使用@+装饰器函数名
标准版的装饰器(不带参数):
def wrapper(f): def inner(*arg,**kargs): '''添加额外的功能:执行被装饰函数以前的操做''' ret = f(*arg,**kargs) '''添加额外的功能:执行被装饰函数以后的操做''' return ret return inner #装饰器的调用 @wrapper def func(): pass
带参数的装饰器
闭包原理,内部函数可以使用外部函数的参数。
def logger(*arg,**kargs): #参数能够本身设定 def wrapper(f): def inner(*arg,**kargs): '''添加额外的功能:执行被装饰函数以前的操做,并可使用传进来的path参数''' ret = f(*arg,**kargs) '''添加额外的功能:执行被装饰函数以后的操做,并可使用传进来的path参数''' return ret return inner return wrapper @loger('传参') #wrapper = loger(),func=wrapper(func()) def func(): pass
自定义模块
模块的本质就.py文件,封装语句的最小单位。模块的分类:内置模块(200种左右)、第三方模块(6000多种)、自定义模块。当python脚本/模块运行时,python解释器会自动将一些模块、函数加载到内存。可用import sys print(sys.modules)
查看
自定义模块:
-
编写自定义模块开头最好用多行注释说明模块内容。
-
模块中出现的变量、函数定义、类等称为模块的成员。
-
模块(.py文件)的运行方式:
- 脚本方式:直接用解释器执行。
- 模块方式(导入方式):被其余的模块导入,为导入它的模块提供资源(变量、函数定义、类定义等)。
-
模块被其余模块导入时,会将模块中的全部代码加载到内存,其中的可执行语句被会当即执行。所以为了方便调试和使用,可用
__name__
属性。将print(__name__)
编写在模块中时,以脚本方式运行打印的是字符串__main__
,以被导入的方式运行时,会打印出模块名。所以模块应包含if __name__=='__main__':
以用来判断是脚本方式运行仍是导入方式,此时当模块被导入时可执行语句不会直接运行。def func(): ...... def main(): pass if __name__=='__main__': main()
导入模块的方式:
-
import xxx
或import xxx,yyy,....
导入一个模块或导入多个模块。常常将import os,sys
这两个模块放在一块导入。可使用别名(alias,缩写为as)导入:import xxx as z
导入xxx模块重命名为z。当运行至此导入模块方法代码时会在内存全局命称空间中开辟以模块名命名的新的名称空间,并将模块中的全部成员加载至命称空间中。被导入的每一个模块都有独立的命称空间。
-
from xxx import y
或from xxx import a,b,c,......
:从某个模块中导入指定的成员或导入多个成员。from xxx import yyy as z
导入xxx模块将成员名重命名为z。当运行至此导入模块方法代码时会在脚本的全局命称空间中建立导入的成员的变量,所以不用使用
模块名.成员名
调用,但用此方法可能会致使命名冲突,后者将前者覆盖。导入后内存全局命称空间中开辟以模块名命名的新的名称空间,变量的内存地址的指向关系仍然不会改变,每一个模块仍都有独立的命称空间。 -
from xxx import *
:默认从某个模块中导入所有可导入的成员。配合__all__
使用,被引用的模块中编写__all__=['','',...]
列表中是可被导入的成员。但__all__
只对此种导入方法起做用,用于表示模块能够被外界使用的成员,元素是成员名组成的字符串,默认不写是能够导入所有成员。
系统导入模块的搜索路径,以import time
示例:先在内存中查看是否有以该模块名命名的命称空间,若是以前成功导入过某个模块,会直接使用已经存在的模块。若没有则再内置模块路径中(在python安装路径中lib和site-packages文件夹下)寻找。若仍没有,就会在sys.path
中寻找。
sys.path:查看sys.path内容,用cmd运行:import sys print(sys.path)
打印出的列表第一个元素是当前执行脚本的路径。列表动态可修改所以可将自定义模块文件夹所在的绝对路径添加到sys.path中以便导入:
import sys sys.path.append('模块文件夹路径')
在不一样的目录下相对导入自定义模块:
相对导入:针对某个项目中的不一样模块之间进行导入,称为相对导入(模块间必须有一个同一个文件夹)。相对导入只有一个语法:from 相对路径 import xxx
相对路径:包含了点号的一个相对路径。
.:表示当前的路径。
..:表示的是父路径
...:表示的是父路径的父路径
..x.y:表示的是父路径下x文件夹下的y文件(夹)
举例:在python文件夹下有t1和t2两个文件夹,t1和t2文件夹下分别有pt1.py和pt2.py两个模块。python文件夹在WorkSpace文件夹下,WorkSpace下有一个main.py文件。
#相对导入(在pt1.py文件中编写): #1.将pt1做为对外界的接入口: from ..t2 import pt2 #..:从当前的路径(不包含当前文件,即/WorkSpace/python/t1)的父目录(/WorkSpace/python/)下找t2,在从t2中找pt2。 #测试相对导入(在main.py文件中编写): import os,sys sys.path.append(os.path.dirname(__file__)) #把项目所在的父路径加到sys.path中。 from python.t1 import pt1 #使用pt1.py模块文件导入的pt2.py模块中的成员: pt1.pt2.成员名 #但不推荐这样写。容易向外界暴露pt2模块。 #更改方法(真正的相对导入): #相对导入(在pt1.py文件中编写): #1.将pt1做为对外界的接入口: from ..t2.pt2 import * #直接导入pt2模块 #测试相对导入(在main.py文件中编写): import os,sys sys.path.append(os.path.dirname(__file__)) #把项目所在的父路径加到sys.path中。 from python.t1 import pt1 #使用pt1.py模块文件导入的pt2.py模块中的成员: pt1.成员名 #成员名:能够是pt1和pt2模块的成员。 #不用相对导入(不推荐): #1.在pt1模块下编写: import os,sys sys.path.append(as.path.dirname(os.path.dirname(__file__))+'/t2') from pt2 import *
经常使用模块
使用导入的模块是否要在其后加():若是是一个类(class)或者是一个函数(function)就要加(),若是是一个属性就不要加括号。
random模块
pseudo-random,伪随机数;提供了随机数获取的方法
- random.random():获取[0.0,1.0)范围内的浮点数。
- random.randint(a,b):获取[a,b]范围内的一个整数。
- random.uniform(a,b):获取[a,b]范围内的一个浮点数数。
- random.shuffle(x):把参数指定的数据中的元素打乱,参数必须是一个可变的数据类型。没有返回值(由于是直接将x打乱,调用改函数后x会被改变,与append无返回值缘由相同。)(不支持元祖,可用sample打乱)
- random.sample(x,k):从x中随机抽取k个数据,组成一个列表返回。
- random.randrange(start,stop,step):生成一个[start,stop)之间以step为步长的随机整数。默认步长为1。
- random.seek(a):设置初始化随机数种子。a,随机数种子,能够是整数或浮点数。使用random库产生随机数不必定要设置随机数种子,若是不设置,random库默认以系统时间产生当作随机数种子。设置随机数种子的好处是能够重复在现相同的随机数序列。
l1 = [1,2,3,4,5,6,] #列表是有序的 s1 = {1,2,3,4,5,6,} s2 = 'wfwhgfwqnbvc阿尔天花板vc' t1 = (1,2,3,4,5,6,) import random random.seed() print(random.random()) print(random.uniform(1,8)) print(random.randint(2,8)) print(random.shuffle(l1)) #只能用于有下标类型,而且能够用x[i],x[j]=x[j],x[i]互换,dict、set、tuple不行。 print(l1) random.shuffle(s2) print(s2) s3 = random.sample(t1,len(t1)) #取样, print(t1)
time模块
封装了获取时间戳和时间戳与字符串形式的一些方法,时间戳:从时间元年(1970年,1月,1日,00:00:00)到如今通过的秒数(毫秒数,不一样系统/编程语言不同。)
import time # 获取时间戳: print(time.time()) # 默认使用当前时间戳, # 获取格式化时间对象(方法:gmtime()、localtime()),格式化时间对象:struct_time: print(time.gmtime()) #接受参数为时间戳,默认不写使用当前时间戳,获取格林威治(GMT)时间。 print(time.localtime()) #接受参数为时间戳,默认不写使用当前时间戳,获取当地时间,tm_hour与格林威治时间(时区差)不一样。 # 格式化时间对象和时间字符串(str)之间的转换。time.strftime(format,str) a = time.localtime() print(time.strftime('%Y-%m-%d %H:%M:%S',a)) #接受两个参数,第一个是时间格式,第二个是格式化时间对象(默认不写用当前的时间戳的格式化时间对象)。 # 时间字符串转换为时间对象(time.strptime(str,format)): print(time.strptime('2000 1 1','%Y %m %d')) #不指定时间用默认值(小时分钟等用0,月份天等用1) # 格式化时间对象转换为时间戳:time.mktime() print(time.mktime(time.localtime())) # 暂停当前程序:time.sleep() 参数为秒 time.sleep(2) #暂停2秒
datetime模块
封装了一些日期和时间相关的类。主要用于数学计算
date类(年月日):
#date类 d = datetime.date(2010,10,10) print(d) #2010-10-10 print(d.year) #2010 print(d.month) #10 print(d.day) #10
time类(时分秒):
#time类 t = datetime.time(10,11,12) print(t) print(t.hour) print(t.minute) print(t.second)
datetime类
dt = datetime.datetime(2010,10,10,11,11,11) print(dt) print(dt.year)
timedelta类: 参与数学运算,建立时间对象(只能和date,datetime,timedelta进行运算),会产生进位,和时间段进行运算的结果类型和另外一个被操做的类型相同。
td = datetime.timedelta(seconds=3) d = datetime.datetime(2000,10,10,10,10,59) res = d+td print(res)
练习:随便给出一年,计算2月份有多少天。
import datetime #1.首先建立出指定年份的3月1号,而后让它往前走一天。 year = int(input("输入年份:")) #2. 建立指定年份的date对象。 d = datetime.date(year,3,1) dt = datetime.timedelta(days=1) res = d-dt #和时间段进行运算的结果类型和前方被减类型相同。 print(res.day)
os模块
和操做系统相关的操做被封装在这个模块中。
和文件相关的:重命名、删除、
import os #删除文件 os.remove() #参数为文件的路径 #重命名文件 os.rename() #两个参数,第一个为文件路径,第二个为文件新名 #删除目录,必须是空目录,在程序中删除不会放在回收站中。 os.removedirs() #一个参数,目录的路径 #使用shutil模块能够删除带内容的目录。 import shutile shutile.rmtree() #一个参数,文件夹目录 os.getcwd() #可查看当前的目录 os.chdir(‘指定目录’) #可切换目录
和路径相关的操做,被封装到另外一个子模块中:os.path
绝对路径:从盘符开始定位的路径;相对路径:从当前文件定位的路径
exists(path) 判断路径是否存在 若文件不存在则为False isdir(s) 判断是否为一个目录 若文件不存在则为False isfile() 判断是不是一个文件 若文件不存在则为False 如下方法不会判读文件是否存在 dirname(path) 取一个路径前的目录(父目录),不会判断目录是否存在, basename(path) 取一个路径中最后的部分 split(path) 分割路径,返回一个二元祖,第一个元素为路径前的(父目录),第二个为路径中最后的部分。 join(path,paths) 合并路径。 abspath(path) 将路径变为绝对路径 isabs() 判断一个路径是否为绝对路径
import os res = os.path.dirname(r'd:/aaa/bbb/ccc/text.py') print(res) #d:/aaa/bbb/ccc res = os.path.basename(r'd:/aaa/bbb/ccc/text.py') print(res) #text.py res = os.path.join('d:\\','aaa','bbb','cc') #有一个转义字符 print(res) #d:\aaa\bbb\cc res = os.path.abspath(r'd:\aaa\bbb\cc') print(res) #D:\aaa\bbb\cc res = os.path.abspath(r'\aaa\bbb\cc') #若是是\开头的路径,默认是在当前盘符下。 print(res) #D:\aaa\bbb\cc res = os.path.abspath(r'aaa\bbb\cc') #若是不是\开头,则是当前脚本的路径。 print(res) #D:\WorkSpace\Python\text1\aaa\bbb\cc
使用os模块获取一个文件路径的父路径:import os os.path.dirname(__file__)
,__file__
:获取模块的路径。import os os.__file__
sys模块
提供了解释器使用和维护的变量和函数;没有提供源码,用c语言编写直接集成在解释器上;默认会导入os模块,但若要使用os模块仍需import os
。
sys.argv
:以当前脚本方式执行程序时,从命令行获取参数。
argv[0]
表示的是当前正在执行的脚本名,argv[1]
表示第一个参数,以此类推。
import sys print("脚本名:",sys.argv[0]) print("第一个参数:",sys.argv[1]) #在命令行运行,传入两个参数,会将两个参数打印出来
sys.path
系统寻找模块的路径,能够经过PYTHONPATH来进行优化。因为是程序执行的时候进行初始化的,因此路径的第一项path[0]始终是调用解释器的脚本所在的路径,若是是动态调用的脚本,或者是从标准输入读取到的脚本命令,则path[0]是一个空字符串,程序中能够随时对这个路径进行修改,已达到动态添加模块路径的目的。
sys.modules
:以字典形式返回系统已经加载的模块。常做为是否从新从新加载模块的判断。
json模块
将数据结构直接转换为字符串用str()
能够,但再将字符串数据转换为原先的数据结构就会出现问题。
l1 = ['ab','cd'] s1 = str(l1) print(s1) #['ab', 'cd'] print(list(s1)) #['[', "'", 'a', 'b', "'", ',', ' ', "'", 'c', 'd', "'", ']']
JavaScript Object Notation:Java脚本兑现标记语言。已经成为一种简单的数据交换格式。将数据转换成特殊字符串,不一样语言都遵循的一种数据转化格式,用于储存dump()和load()或dumps()和loads()
或网络传输dumps()和loads()
。
json序列化:
import json s = json.dumps([1,2,3,4,]) #将指定的对象转换成json格式的字符串,仍然放在内存中 print(s,type(s)) #[1, 2, 3, 4] <class 'str'> #元祖序列化后变成列表 import json s = json.dumps((1,2,3,4,)) print(s,type(s)) #[1, 2, 3, 4] <class 'str'> #集合不可一被json序列化 #将结果直接写到文件中:json.dump(obj,fb) with open('a.txt',mode='at',encoding='utf-8') as f: json.dump(['1,2,3,'],f)
json反序列化:
import json res = json.dumps([1,2,3,]) lst = json.loads(res) #从文件中反序列化:json.loads(fb) with open('a.txt',encoding='utf-8') as f: res = json.load(f)
dump()和load()
只能一次性写,一次性读。把须要序列化的对象,经过dumps()和loads()
的方式,可实现屡次读或写,写入时要换行,才能读出再转化。
with open('a.txt',mode='wt',encoding='utf-8') as f: for i in range(10): f.write(json.dumps()+'\n') with open('a.txt',encoding='utf-8') as f: for i in f: json.loads(i.strip()) # 或json.loads(i),默认去除换行
pickle模块
可将python中全部的数据类型转换成字节串
元祖在pickle中转换不会改变类型。
pickle也能够转换set类型
pickle中dump()和load()
能够屡次读写一个文件。dump(s,f)
能够写入python中的任何对象(变量、函数、类等)
import pickle bys = pickle.dumps((1,2,3)) #转化为字节 res = pickle.loads(bys) print(type(res),res) #<class 'tuple'> (1, 2, 3) #把pickle序列化内容写入文件中: with open('b.txt',mode='wb') as f: pickle.dump([1,2,3],f) #从文件中反序列化pickle数据: with open('b.txt',mode='rb') as f: pickle.load(f)
pickle与json的比较
json:
- 不是全部的数据类型均可以序列化
- 不能屡次对同一个文件序列化
- json数据能够跨语言。
- json序列化只支持部分python数据结构:dict、tuple、int、float、True、False、None
pickle:
- 全部的python类型都能序列化,结果为字节串。
- 能够屡次对同一个文件序列化
- 不能跨语言,只能在python中使用。
hashlib模块
封装一些用于加密的类。加密的目的:用于判断和验证,而非解密。给一个数据进行加密,用另个加密的结果和第一次加密的结果进行对比,若是加密结果想同,说明原文相同。
特色:
- 把一个大的数据切分红不一样的块,分别对不一样的块进行加密,再汇总的结果和直接对总体数据加密的结果是一致的。
- 单向加密,不可逆。
- 原始数据的一点小的变化,将致使加密结果很是大的差别。
md5加密算法:
import hashlib #获取一个加密对象 m = hashlib.md5() #使用加密对象的update进行加密 m.update(b'abc') #将abc变为字节,如有中文则为'abc'.encode('utf-8') #经过hexdigest()获取加密。 res = m.hexdigest() print(res) #900150983cd24fb0d6963f7d28e17f72
给一个数据加密的步骤:
-
获取一个加密对象,不仅是有md5,还有sha系列
sha224', 'sha256', 'sha384', 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 'sha512'
等,随着sha系列数字越高,加密越复杂,。在建立加密对象时,能够指定参数,使加密程度更高。import hashlib m = hashlib.md5('abc'.encode('utf-8')) m.update('qaz'.encode('utf-8')) print(m.hexdigest())
-
使用加密对象的
update()
方法进行加密。加密对象能够调用屡次(即为把一个大数据切分红小数据,再把小数据进行累次加密,不是对同一个数据屡次加密)。都是对字节进加密。相同的加密对象将字节转化成固定长度的字符串。 -
一般经过
hexdigest()
获取加密字符串,也能够经过digest()
获取加密字节串。不一样加密算法的加密结果长度不一样,随着加密结果的变长,加密时间也会变长。
#注册和登陆程序 import hashlib def register(): username = input('输入用户名:') passwd = input("输入密码:") get_passwd = get_md5(passwd) #加密 with open('login',mode='at',encoding='utf-8') as f: #写入文件 f.write(f'{username}|{get_passwd}\n') def login(): username = input('输入用户名:') passwd = input('输入密码:') get_passwd = get_md5(passwd) res = f'{username}|{get_passwd}\n' with open('login',mode='rt',encoding='utf-8') as f: for line in f: if res == line: return True else:return False def get_md5(passwd): m = hashlib.md5('12') #再次加密 m.update(passwd.encode('utf-8')) return m.hexdigest() while True: op = input('1.注册 2.登陆 3.退出') if op == '1': register() elif op == '2': res = login() if res: print('登陆成功') else: print('登陆失败,请从新登陆') elif op == '3': break else:print("您输入的有误,请从新输入")
文件的校验:
Linux中一切皆文件:文本文件,非文本文件,音频,视频,图片……。不管下载的视频仍是国外的软件每每都会有一个md5值。
collections模块
封装了一些经常使用的容器类。
namedtuple()
:命名元祖,可使用属性的方式引用元祖中的数据。
import collections as co: #namedtuple()的返回值是一个类 Rectangle = co.namedtuple('Rectangle_class',['length','width']) #第一个参数是对类名的说明信息,不能有空格。namedtuple()的返回值是赋值给了自定的类名。 r = Rectangle(10,5) #经过属性访问元祖的元素 print(r.length) print(r.width) #经过引所的方式访问元素 print(r[0])
defaultdict()
:默认值字典
#defaultdict():(自定义)函数(不能有参数)充当第一个参数 d = co.defaultdict(lambda :'hello',name='aa',age='10') print(d['na']) #hello 若无要查询的键,不会报错,会根据函数返回必定的值,且会自动将此键值增长至字典中 print(d) #defaultdict(<function <lambda> at 0x000001F90D30D378>, {'name': 'aa', 'age': '10', 'na': 'hello'})
Counter()
:计数器,返回值是字典,必须使用可哈希的数据。
c = co.Counter('asasasasaszszxaxzsxazsx') print(c) #Counter({'s': 8, 'a': 7, 'z': 4, 'x': 4}) print(c.most_common(3)) #[('s', 8), ('a', 7), ('z', 4)]
re模块
findall()
:返回全部符合匹配结果的列表,只有一个元祖元素,每一个分组是元祖中的每一个元素。若是正则进行分组,则只显示分组里的内容。若不想让每一个分组返回;取消分组优先,在分组括号中增长?:
search()
:返回一个对象(变量),需和group()配合。若是进行分组,则只显示第一个分组里的内容,但能够经过group(n)
获取第n个分组的内容(n>0),默认为0,返回全部的分组结果。
设置参数flags=re.S
可以让.
匹配任意内容,包括换行符。
import re ret = re.search('(d+)\w','123123adas1213as') if ret: #若ret为None直接打印ret.group()就会报错。 print(ret.group())
split()
:能够根据正则表达式切割字符串,返回分组,若给正则加上分组,则会将分组中匹配的内容保留至列表中。
sub()
:替换。re.sub('\d','a','123qwe21',1)
将数字替换成a,只替换1次。
subn()
:替换,返回二元祖。第一个为替换结果,第二个为替换次数。
match()
:只匹配开头,经过group()
取值,至关于使用search()
方法在正则表达前使用^
。用来规定字符串必须是什么。
时间:完成一个程序所须要的代码行数;在执行代码的过程当中,底层程序是如何工做的。
空间:占用的内存条资源,程序的执行效率。
compile()
:假如同一个正则表达式要被屡次使用,可用re.compile('正则表达式')
可节省了屡次解析同一个正则表达式的时间。从时间上提升了效率。若是不重复使用正则,则不会节省时间。
finditer()
:将正则表达式的匹配全部的结果变成一个迭代器,用.group()
每一个获取结果。节省了空间。
import re ret = re.compile('\d') res = ret.finditer('qaq112qsx123sxa') for i in res: print(r.group())
分组命名:在分组中取名?P<分组名>
将名字放在<>
之间。能够用group('分组名')
获取。分组匹配的内容能够被引用。
import re exp = '<h1>123qdwdcasd</h1>' ret = re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',exp) #第二个分组引用的是第一个分组匹配的内容。 print(ret)
分组间也能够用\n
引用:n为要引用的第几个分组。
import re exp = '<h1>123qdwdcasd</h1>' ret = re.search(r'<(?P<tag>\w+)>.*?</\1>',exp) #在python中`\一、\二、\3等是有特殊意义的,所以要表示在正则中的意义须要转义,即加r或\ ret = re.search('<(?P<tag>\w+)>.*?</\\1>',exp)
shutil模块
import shutil # 拷贝文件,shutil.copy2('原文件', '现文件') shutil.copy2('file', 'temp') # 拷贝目录,shutil.copytree("原目录", "新目录",ignore=shutil.ignore_patterns(*args)) #ignore,忽略要copy的文件 shutil.copytree("/Users/jingliyang/PycharmProjects", "logging模块2", ignore=shutil.ignore_patterns('*.py')) #*.py:全部的以.py结尾的。 # 删除目录,shutil.rmtree("temp", ignore_errors=True) ignore_errors:是否忽略一些错误。 shutil.rmtree("logging模块2", ignore_errors=True) # 移动文件/目录,并能够重命名。 shutil.move("logging模块", "logging2", copy_function=shutil.copy2) # 获取磁盘使用空间 total, used, free = shutil.disk_usage(".") .:查看当前磁盘的空间,也能够用:'c:\\' print("当前磁盘共: %iGB, 已使用: %iGB, 剩余: %iGB"%(total / 1073741824, used / 1073741824, free / 1073741824)) # 压缩文件,shutil.make_archive('压缩文件夹的名字', 'zip','待压缩的文件夹路径') shutil.make_archive('logging2', 'zip','/Users/jingliyang/PycharmProjects/面试题/经常使用模块/随机数') # 解压文件,shutil.unpack_archive('zip文件的路径.zip','解压到目的文件夹路径') shutil.unpack_archive('/Users/jingliyang/PycharmProjects/面试题/经常使用模块/shutil模块/logging2.zip','/Users/jingliyang/PycharmProjects/面试题/经常使用模块/shutil模块/tmp')
logging模块
log:用来记录用户的行为,以便数据分析,操做审计;用来排查代码中的错误。
基本配置:
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名称:用户输出消息。
灵活配置日志级别,日志格式,输出位置:
import logging file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) logging.error('你好')
日志切割
import time import logging from logging import handlers sh = logging.StreamHandler() #同时输出到屏幕 rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5) #maxBytes:按照文件的大小切割,backupCount最多保留的文件数 fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8') #when='s'按时间切割,默认为小时。interval=5每5秒切割一次。 logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s[%(lineno)d] -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[fh,sh,rh], level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error('KeyboardInterrupt error %s'%str(i))
配置参数:
logging.basicConfig()函数中可经过具体参数来更改logging模块默认行为,可用参数有: filename:用指定的文件名建立FiledHandler,这样日志会被存储在指定的文件中. filemode=:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”(filemode='w')。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger的日志级别 stream:用指定的stream建立StreamHandler。能够指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串: %(name)s Logger(用户,管理员为root)的名字 %(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用户输出的消息
logger对象配置
import logging logger = logging.getLogger() # 建立一个handler,用于写入日志文件 fh = logging.FileHandler('test.log',encoding='utf-8') # 再建立一个handler,用于输出到控制台 ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setLevel(logging.DEBUG) fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) #logger对象能够添加多个fh和ch对象 logger.addHandler(ch) 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)单对文件流设置某个级别。
第二章 面向对象
待续….