第一章 python基础
初识
-
cpu 内存 硬盘 操作系统
cpu:计算机的运算和计算中心,相当于人类大脑。
内存:暂时存储数据,临时加载数据应用程序,运行速度快,高铁,断电即消失,造价很高。
硬盘:磁盘,长期存储数据。
操作系统:一个软件,连接计算机的硬件与所有软件之间的一个软件。 -
python的编程语言分类
-
编译型:将代码一次性全部编译成二进制,然后再执行。优点:执行效率高。缺点:开发效率低,不能跨平台。代表语言:C
-
解释型:逐行解释成二进制,逐行运行。优点:开发效率高,可以跨平台。缺点:执行效率低。代表语言:python。
-
-
python的种类
- Cpython:官方推荐解释器。可以转化成C语言能识别的字节码。
- Jpython: 可以转化成Java语言能识别的字节码。
- Ironpython:可以转化成.net语言能识别的字节码
-
pypy: 动态编译。
......
-
变量:只是指向某种数据
-
常量:python中没有真正的常量,为了应和其他语言的口味,全部大写的变量称之为常量。
-
while/for 的else:如果循环没有被break终止则else语句会被执行,如果while被break终止,则不执行else语句。
-
运算符:算数运算符+、-等;比较运算符>、==等;赋值运算符=、+=等;逻辑运算符not、and、or;成员运算符in、not in。
and or not- 在没有()的情况下,优先级: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-8、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()方法),若果没有给出索引值则默认删除最后列表的一个元素,有返回值,返回删除的元素。
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) ,前一集合独有的元素