01 python基础
垃圾回收机制
1.引用计数: 内存中的数据如果没有任何的变量名与其有绑定关系,那么会被自动回收
2.标记清除: 当内存快要被某个应用程序占满时会自动触发,停止程序的运行,检测所有变量与值的绑定关系,给引用计数为0的值打上标记最后一次性清除
3.分代回收: 根据值存活时间的不同,划为不同的等级,等级越高垃圾回收机制扫描的频率越低
变量和常量
变量
变量名的命名规范:
1.只能包含数字,字母,下划线
2.数字不能开头
3.关键字不能作为变量名
通常变量名的命名有两个流派:
驼峰体(前端语言js推荐的命名方式)
userName
下划线(python推荐的命名方式)
user_name
注意: 变量必须先定义后调用,变量名一定要起的有意义(见名知意),千万不要用中文
变量的三要素:
id(): 返回的是一串数字,可以直接理解为内存地址
type(): 返回的是该变量对应的数据的类型
value: 该变量指向的内存当中的数据值
小整数池(1-256):
>>> a = 257
>>> b = 257
>>> id(a)
2919979319120
>>> id(b)
2919979576208
>>> c = 256
>>> d = 256
>>> id(c)
1642892736
>>> id(d)
1642892736
常量
常量(不可变的量)
python里面压根没有常量
通常将全大写的变量名看作常量(python程序员约定俗成的)
输入输出
输入
name = input('please input you username>>>: ')
格式化输出
name = 'jll'
age = 18
print('my name is',name,'my age is',age) # my name is jll my age is 18
# 占位符 %s %d
print('my name is %s my age is %s'%(name,age)) # my name is jll my age is 18,谁先来谁先坐,个数必须一致不能多也不能少
print('my name is %s my age is %d'%(name,age)) # %d只能给数字占位,%s可以给任意数据类型占位
print('%08d'%123) # 00000123,整数是8位,传入的数不够八位前面用0补全,超出8位,是多少就是多少
数据类型
数值类型
整型(不可变)
age = 18 # age = int(18)
方法
# int()
print(int()) # 0
print(int(3)) # 3
print(int(3.6)) # 3
print(int('1100',2)) # 12 二进制'1100'转成十进制
print(int('14',8)) # 12
print(int('c',16)) # 12
# bin()
print(bin(12)) # 0b1100 十进制转二进制,0b表示后面的数字是二进制数
# oct()
print(oct(12)) # 0o12 十进制转八进制,0o表示后面的数字是八进制数
# hex()
print(hex(12)) # 0xc 十进制转十六进制,0x表示后面的数字是十六进制数
浮点型(不可变)
salary = 1.11 # salary = float(1.11)
复数
a = 1-2j
print(type(a)) # <class 'complex
print(a.real) # 1.0 查看实部
print(a.imag) # -2.0 查看虚部
长整型(python2)
a = 123
print(type(a)) # <type 'int'>
b = 12345678910111213141516171819 # 定义长整型: b = 1L
print(type(b)) # <type 'long'> 只有python2中才有长整型的概念,python3里面只有整型
字符串(不可变 有序)
# 定义,之所以有三种定义方式是考虑到用户在输入的文本中也需要用到引号
# 第一种 单引号
s1 = '我是字符串,jason说: "天下无敌"' # 我是字符串,jason说: "天下无敌",s1 = str('XXX')
# 第二种 双引号
s2 = "我是字符串,jason说: '天下无敌'" # 我是字符串,jason说: '天下无敌'
# 第三种 三引号(可以是单也可以是双,并且可以写多行,但是不能混合使用)
s3 = '''
我是字符串
并且可以写多行
'''
s4 = """
我是字符串
并且可以写多行
"""
# python中的字符串支持加和乘操作
s5 = 'hello'
s6 = 'world'
print(s5+s6) # helloworld
print(s5*3) # hellohellohello
# str() 所有类型都可以转成字符串类型
s1 = str([1,2,3,4])
print(type(s1)) # <class 'str'>
内置方法
# 1. strip() lstrip() rstrip()
# 默认去除字符串首尾的空格,也可指定其它符号
print(' jason '.strip()) # jason
print('$$jason$$$'.strip('$')) # jason
print('% ¥#jason&*)'.strip('% ¥#*')) # jason& 指定去除多个字符
print('$$jason$$$'.lstrip('$')) # jason$$$$ 只去除左边字符
print('$$jason$$$'.rstrip('$')) # $$$$jason 只去除右边字符
# 2. split() rsplit()
# 切分,针对按照某种分隔符组织的字符串,可以用split将其切分成列表,进而进行取值,如果不指定切割个数那么split和rsplit效果是一样
data = 'jason|123|handsome'
print('data'.split('|')) # ['jason','123','handsome'] 切割的顺序是从左往右的
username,password,info = data.split('|')
print(data.split('o',1)) # ['jas','n|123|handsome'] 从左往右只切一个
print(data.rsplit('o',1)) # ['jason|123|hands','me'] 从右往左只切一个
# 3. lower() upper()
print('JaS1oN'.lower()) # jas1on 转小写
print('JaS1oN'.upper()) # JAS1ON 转大写
# 4. startswith() endswith()
print('egon is dsb'.startswith('egon')) # True 判断字符串是否以什么什么开头
print('egon is dsb'.endswith('n')) # False 判断字符串是否以什么什么结尾
# 5. format()
# 第一种,按位置占位,跟%s原理一致
str1 = 'my name is {} my age is {}'.format('jason',18)
# 第二种,按索引占位
str1 = 'my name is {1} my age is {0}'.format('egon',18) # my name is 18 my age is egon
# 第三种,指名道姓占位(关键字传参)
str1 = 'my name is {name} my age is {age}'.format(name='jason',age=18)
# 6. join()
# 将容器类型中的多个元素通过指定字符拼接成一个字符串,join拼接时容器中的每个元素类型都要是一样的
res_list = ['jason','123','handsome']
res_str = '$'.join(res_list)
print(res_str) # jason$123$handsome
# 7. replace 替换
str = 'egon is dsb and egon has a BENZ'
print(str.replace('egon','kevin')) # kevin is dsb and kevin has a BENZ
print(str.replace('egon','kevin',1)) # kevin is dsb and egon has a BENZ 从左往右只替换一个
# 8. isdigit() 判断字符串中包含的是否为纯数字
age = input('>>>: ')
print(age.isdigit())
# 9. find() rfind() index() rindex()
# find和index的区别是,find找不到返回-1,index找不到报错
s = 'kevin is dsb o and kevin is sb'
print(s.find('dsb')) # 返回的是d字符所在的索引值
print(s.find('xxx')) # 找不到不报错返回-1
print(s.find('i',0,3)) # 通过索引来限制查找范围
print(s.index('o')) # 返回所传字符所在的索引值
print(s.index('xxx')) # 找不到则报错
print(s.index('v',0,3)) # 通过索引来限制查找范围,顾头不顾尾
# 10. count()
print('kevin is dsb o and kevin is sb'.count('n')) # 统计字符出现的次数
# 11. center() ljust() rjust() zfill()
print('jason.center(12,'*')) # ***jason****
print('jason.ljust(12,'$')) # jason$$$$$$$
print('jason.rjust(12,'$')) # $$$$$$$jason
print('jason.zfill(12)) # 0000000jason
# 12. expandtabs() 指定tab键的空格数
s10 = 'a\tbc'
print(s10) # a bc
print(s10.expandtabs(6)) # a bc
# 13. captalize() swapcase() title()
print('hElLo WoRLD sH10'.capitalize()) # Hello world sh10 首字母大写
print('hElLo WoRLD sH10'.swapcase()) # HeLlO wOrld Sh10 大小写互换
print('hElLo WoRLD sH10'.title()) # Hello World Sh10 每个单词的首字母大小
# 14. isnumeric() isdecimal() isdigit() is数字系列,判断是否为数字
num1=b'4' # bytes
num2=u'4' # unicode python3中无需加u就是unicode
num3='壹' # 中文数字
num4='Ⅳ' # 罗马数字
# ''.isnumeric(): unicode,中文数字,罗马数字
print(num2.isnumeric()) # True
print(num3.isnumeric()) # True
print(num4.isnumeric()) # True
# ''.isdecimal(): unicode,只识别普通的阿拉伯数字
print(num2.isdecimal()) # True
print(num3.isdecimal()) # False
print(num4.isdecimal()) # False
# ''.isdigit(): bytes,unicode,通常情况下使用isdigit就已经满足需求了
print(num1.isdigit()) # True
print(num2.isdigit()) # True
print(num3.isdigit()) # False
print(num4.isdigit()) # False
# 15. isalpha() 判断字符串是否包含数字,包含返回False,不包含返回True
print('a'.isalpha()) # True
print('a'.isalpha()) # False
列表(可变 有序)
l = [123,3.1,'dbj',[11,22]] # l = list([...])
print(l[3][0]) # 11
# 能够被for循环的就能够被list转换,list内部原理就是for循环取值,然后一个个塞到列表中去
print(list('abc')) # # ['a','b','c']
print(list({'name': 'jason','password': '123'})) # ['name','password']
内置方法
# 1. append() insert() extend() 往列表中添加元素
l = [11,22,33,44,55]
l.append(66) # [11,22,33,44,55,66] 注意append只能将被添加的数据当作列表的一个元素
l = [11,22,33,44,55]
l.insert(2,96) # [11,22,96,33,44,55] 通过索引在任意位置添加元素,注意insert只能将被添加的数据当作列表的一个元素
l = [11,22,33,44,55]
l1 = [88,77,66]
l.append(l1) # [11,22,33,44,55,[88,77,66]]
l.insert(-1,l1) # [11,22,33,44,[88,77,66],55]
l.extend(l1) # [11,22,33,44,55,88,77,66] 添加容器类型数据,内部原理for循环l1一个个追加到列表的尾部
# 2. del pop() remove() 删除列表元素
l = [11,22,33,44,55]
del l[2] # del适用于所有烈性的删除操作,没有返回值
print(l) # [11,22,44,55]
l = [11,22,33,44,55]
res1 = l.pop() # l=[11,22,33,44] res1=55 尾部弹出,会将弹出的值返回给调用者
res2 = l.pop() # l=[11,22,33] res2=44
res3 = l.pop() # l=[11,22] res3=33
l = [11,22,33,44,55]
res = l.pop(2) # l=[11,22,44,55] res=33 可以指定索引,按照索引弹出元素
l = [11,22,33,44,55]
l.remove(33) # 指定要删除的元素的值,没有返回值
print(l) # [11,22,44,55]
# 3. count()
print(['a','b',1,8,8,'a'].count(8)) # 2
# 4. clear() 清空列表
l = ['a','b',1,8,8,'a']
l.clear()
print(l) # []
# 5. reverse() # 将列表反转
l = ['a','b',1,8,8,'a']
l.reverse()
print(l) # ['a',8,8,1,'b','a']
# 6. sort() 排序,默认情况下是从小到大(升序)
l1 = [43,6,1,7,99]
l1.sort()
print(l1) # [1,6,7,43,99]
l1.sort(reverse=True) # 可以通过指定参数来修改默认的排序规则(降序)
print(l1) # [99,43,7,6,1]
# 队列,先进先出
l1 = []
l1.append('first')
l1.append('second')
l1.append('third')
print(l1) # ['first', 'second', 'third']
print(l1.pop(0)) # first
print(l1.pop(0)) # second
print(l1.pop(0)) # third
# 堆栈,先进后出
l1.append('first')
l1.append('second')
l1.append('third')
print(l1) # ['first', 'second', 'third']
print(l1.pop()) # third
print(l1.pop()) # second
print(l1.pop()) # first
布尔
# 如果变量名存储的值是布尔值的话,那么约定俗成的变量名统一用is_开头
is_tag = True # tag = bool(True)
x = 10
y = 20
print(x == y) # False 单个等号是赋值,两个等号是比较,比较的仅仅是值是否相等
print(x is y) # False 比较的是两个变量对应的id是否相等
"""
id相等的情况下,值一定相等
id不相等的情况下,值有可能相等
"""
元祖(不可变 有序)
age=(11,22,33,44) # 本质 age=tuple((11,22,33,44))
t1 = tuple(1) # 报错,必须传容器类型
n = ('a') # 定义元组时,当只有一个元素且没有用逗号时,则不是定义成元组,而是会把()去掉定义成数值或字符串等
n1 = (1)
n2 = ('a',)
n3 = (1,)
print(type(n),type(n1),type(n2),type(n3)) # <class 'str'>,<class 'int'>,<class 'tuple'>,<class 'tuple'>
# 在定义容器类型的时候,哪怕内部只有一个元素,你也要用逗号隔开区分一下(******)
t = (1, 2, 3, 'a', 'b', [1, 2, 3])
t[1] = 'hahah' #元组不能改,报错
del t[-1] # 报错
t[-1][0] = 'hahah' #当元组里的元素是可变的容器类型则可以改
t[-1].append(4)
print(t) # t = (1, 2, 3, 'a', 'b', ['hahah', 2, 3,4])
内置方法
# 1. count()
t = (1, 2, 3, 'a', 'b', [1, 2, 3])
print(t.count('a')) # 1
# 2. index()
t = (1, 2, 3, 'a', 'b', [1, 2, 3])
print(t.index('a')) # 返回所传字符所在的索引值
print(t.index('xxx')) # 找不到则报错
print(t.index('a',0,3)) # 通过索引来限制查找范围,顾头不顾尾
字典(可变 无序)
key: value键值对
key是对value的描述,key通常情况下是字符串
key不能重复,要唯一标识一条数据,如果重复了,会按照最后一组重复的键值对存储
d = {'name': 'jason','password': 123} # d = dict({'name': 'jason','password': 123})
# 定义
# 方式一:
d1 = {'name': 'jason','password': 123}
# 方式二:
d2 = dict(name='jason',password=123)
# 方式三(了解):
l = [
['name','jason'],
['password',123]
]
d3 = dict(l)
d4 = dict([('a',1),('b',2),('c',3)])
print(d4) # {'a': 1, 'b': 2, 'c': 3}
# 按key取值、改值、添加值
d = {'name': 'jason','password': '123'}
d['name'] = 'egon'
print(d['name']) # egon,key不存在则报错,建议用get()
d3['age'] = 18 # 赋值语句当key不存在时,会自动新增一个键值对(******)
print(d3) # {'name': 'egon','password': '123','age': 18},id不变
# 删除
d = {'name': 'jason','password': '123'}
del d['name']
print(d) # {'password': '123'}
d = {'name': 'jason','password': '123'}
d.pop('name')
print(d) # {'password': '123'}
d = {'name': 'jason','password': '123'}
print(d.pop('name')) # jason 弹出仅仅是value
print(d.pop('age')) # 当键不存在的时候直接报错
d = {'name': 'jason','password': '123'}
d.clear()
print(d) # {}
内置方法
# 1. 键keys(),值values(),键值对items()
d = {'name': 'jason','password': 123}
print(d.keys()) # dict_keys(['name', 'password'])
print(d.values()) # dict_values(['jason', 123])
print(d.items()) # dict_items([('name', 'jason'), ('password', 123)])
# 2. get() 根据key获取value(*****)
d = {'name': 'jason','pwd': 123}
print(d['age']) # key不存在则报错
print(d.get('name')) # jason
print(d.get('age')) # None 当字典的key不存在不报错,返回None
print(d1.get('name','key不存在')) # jason
print(d1.get('age','key不存在')) # key不存在 get可以传第二个参数,当key不存在时,返回第二个参数
# 3. formkeys() 快速创建一个字典
l = ['name','password','age']
print(dict.fromkeys(l,None)) # {'name': None,'password': None,'age': None}
print(dict.fromkeys(l,123)) # {'name': 123,'password': 123,'age': 123}
d = dict.fromkeys(l,[]) # 此时name、password、age指向的是同一个列表,当name的列表值改变时,password和age也会跟着改变
print(d) # {'name': [],'password': [],'age': []}
d['name'].append('jll')
print(d) # {'name': ['jll'],'password': ['jll'],'age': ['jll']}
# 4. update() key存在则修改,不存在则新增
d = {'name': 'jason','age': 18}
d.update({'age': 28,'hobby': 'study'})
print(d) # {'name': 'jason', 'age': 28, 'hobby': 'study'}
集合(可变 无序)
# 作用: 去重,关系运算
# 集合是可变类型,但每个元素必须是不可变类型(整型、浮点型、字符串、布尔、元组)
# 没有重复的元素
# 定义:
s = {1,2,3,4,5} # s = set({1,2,3,4,5}),set括号内必须是支持for循环的数据类型
print(set('hello')) # {'h','e','l','l','o'}
x = {} # <class 'dict'> 仅仅只写一个大括号,python默认将它当做字典类型
s1 = set() # 在定义空集合时只能用关键字set
内置方法
# 1. add() 添加元素
s = {1,2,3}
s.add(666)
print(s) # {1,2,3,666}
s.add((11,22))
print(s) # {1,2,3,(11,22),666} 将容器类型也当成一个元素传入
# 2. remove() 删除,不存在则报错
s = {1,2,3}
print(s.remove(1))
print(s) # {2,3}
# 3. discard() 删除,不存在不报错
s = {1,2,3}
s.discard(888)
print(s) # {1,2,3}
共有使用和方法
# for循环
#(字符串、列表、元祖、字典(循环的是key))
for i in 'jason':
print(i)
# 按索引取值,若为可变类型即可以存(正向取+反向取)
#(字符串、列表、元祖)
s = 'hello big baby~'
print(s[0],s[-1],s[-2]) # h ~ y
l = [1,2,3,4]
l[-1] = 69
print(l) # [1,2,3,69]
# 切片(顾头不顾尾,步长为负数代表从右往左切)
#(字符串、列表、元祖)
s = 'hello big baby~'
print(s[0: 5]) # hello
print(s[0: 10: 1]) # hello big,步长不写默认是1
print(s[0: 10: 2]) # hlobg,步长表示隔几个取一个
print(s[0: 5: -1]) # 没有值
print(s[5: 0: -1]) # 空格olle,骨头不顾尾
print(s[-1: -10: -1]) #~ybab gib
print(s[0: : ]) # hello big baby~ l[0: : ]即l[0: 15: 1],即到列表尾部,步长为1
print(l[-1: : -1]) # ~ybab gib olleh 把字符串反过来
# len() 长度
#(字符串、列表、元祖、字典、集合)
print(len('hello big baby~')) # 15
print(len([1,2,3,4])) # 4
# in、not in 成员运算
#(字符串、列表、元祖、字典(只能判断key)、集合)
print('g' in 'egon is dsb and egon is sb') # True
print('jason' not in 'egon is dsb and egon is sb') # True
print(5 in [1,2,3,4]) # False
# del 删除,适用于所有类型,没有返回值
s = 'jll'
del s
l = [11,22,33,44,55]
del l[2]
print(l) # [11,22,44,55]
# enumerate()
# 可用于 字符串、列表、元组、字典
d = {'name': 'jll', 'age': 18}
for i,j in enumerate(d):
print(i,j)
"""
0 name
1 age
"""
运算符
基本运算
print(10 / 3) # 除,结果保留小数部分
print(10 // 3) # 除,只保留整数部分
print(10 % 3) # 取余数
print(2**3) # 2的三次方
# python对数字的敏感度不是很高(存储的数字不精确)
增量运算
xxx += 1 # xxx = xxx + 1
xxx -= 10 # xxx = xxx - 10
xxx *= 2 # xxx = xxx*2
比较运算
# 比较运算: == != > < >= <=
# 数字之间可以互相比较大小
print(10 != 3.1) # True
# a = 'hello'
# b = 'z'
# print(b > a) # True 拿hello第一个字母h的ASCII码104和z的ASCII码122比较,了解
# ASCII码,A-Z a-z,z对应的数字最大,A对应的数字最小
赋值运算
name = 'jll'
age = 18
链式赋值
a = 100
b = a
c = b
x = y = z = 8000
交叉赋值
# 切换m n对应的值
m = 80
n = 70
# 第一种:
o = m
m = n
n = o
# 第二种: 交叉赋值
m,n = n,m
解压赋值
# 适用于 字符串、列表、字典、元组、集合
l = [1,2,3,4]
a,b,c,d = l # 前面的变量个数与后面的元素个数必须相等
print(a,b,c,d) # 1 2 3 4
a,_,_,b = l # 只把l的第一个和最后一个元素分别赋值给a和b
print(a,d) # 1 4
print(_) # 3
a,*_,b = l # 只把l的第一个和最后一个元素分别赋值给a和b
print(a,b) # 1 4
print(_) # [2,3]
逻辑运算
# 与 或 非 and or not
print( 1 > 0 and 3 > 4) # False and两边必须同时成立,结果才成立
print( 1 > 0 or 1 > 0 and 3 > 4) # True or只要有一边成立即成立,后面的无需再看
print(not 1 > 3) # True 结果取反
if判断和for循环while循环和break、continue字段
if、for、while自己可嵌套也可互相嵌套
if判断
if
if else
if elif elif... else
today = input('pleast input today>>: ')
if today in ['Monday','Tuesday','Wednesday','Thursday','Friday']:
print('上班')
elif today in ['Saturday','Sunday']:
print('出去嗨')
while循环
flag = True # 定义一个全局的标志位
while flag:
username = input("please input your username>>>: ")
password = input("please input your password>>>: ")
if username == 'jason' and password == '123':
print('欢迎老板,很高兴为您服务')
while flag:
cmd = input('please input your command>>>: ')
if cmd == 'q':
flag = False
print('%s is running'%cmd)
else:
print('没钱滚蛋~')
print("到点了")
# while+else
n = 1
while n < 5:
if n == 3:
break
print(n)
n += 1
else:
print('while循环正常结束了')
for循环
# 字典在被for循环的时候,只会返回出它的key,value是不会主动暴露给用户的
# 用for循环循环打印1~10
print(range(1,10)) # 顾头不顾尾
for i in range(1,10):
print(i)
# for+else
name_list = ['nick','jason','tank','sean']
for name in name_list:
if name == 'jason':
break
print(name)
else:
print('for循环正常结束了')
"""
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
"""
for i in range(1,10):
for j in range(1,i+1): # 内存循环的range条件是根据外层循环决定的
print('%s*%s=%s'%(j,i,i*j),end=' ') # print会换行,end即不换行以指定的字符结束
print()
''' max_level=5
* current_level=1 空格数=4 星号=1
*** current_level=2 空格数=3 星号=3
***** current_level=3 空格数=2 星号=5
******* current_level=4 空格数=1 星号=7
********* current_level=5 空格数=0 星号=9
'''
max_level=5
for current_level in range(1,max_level+1):
# 先不换行打印空格
for x in range(max_level-current_level):
print(' ',end='')
# 再不换行打印*
for y in range(2*current_level - 1):
print('*',end='')
print()
# 冒泡排序法
"""
第一圈:
[2,1,3,5]
第一次
[2,1,3,5]
第二次
[2,3,1,5]
第三次
[2,3,5,1]
次数为: 元素个数 - 1 - (圈数索引为0)
第二圈:
[2,3,5,1]
第一次
[3,2,5,1]
第二次
[3,5,2,1]
次数为: 元素个数 - 1 - (圈数索引为1)
第三圈:
[3,5,2,1]
第一次
[5,3,2,1]
次数为: 元素个数 - 1 - (圈数索引为2)
总结规律:
需要两层循环:
外层控制圈数
内层控制次数
圈数: 元素个数 - 1
次数: 元素个数 - 1 - (圈数索引: 0 1 2...)
"""
ls = [10,46,82,3,60]
for i in range(len(ls)-1):
for j in range(len(ls)-1-i):
# 升序,如果前面的大于后面的则交换位置
if ls[j] > ls[j+1]:
ls[j],ls[j+1] = ls[j+1],ls[j]
print(ls) # [3,10,46,60,82]
字符编码
# python解释器运行一个py文件的步骤
1.将python解释器的代码由硬盘读到内存
2.将xxx.py以普通文本文件形式读到内存
3.python解释器读取文件内容,识别python语法,执行相应操作
# ASCII码
用八位二进制表示一个英文字符,所有的英文字符+符号最多也就125位左右
# GBK
用2Bytes表示一个中文字符(最多能表示65535个字符),还是用1Bytes表示一个英文字符
日本人 shift
韩国人 fuck
# 万国码unicode(内存的编码)
统一用2Bytes表示所有的字符
unicode的两个特点:
1.用户在输入的时候,无论输什么字符都能够兼容unicode
2.其他国家编码的数据由硬盘读到内存的时候unicode与其他各个国家的编码都有对应关系
# utf-8(硬盘的编码)
当内存中unicode编码格式的数据存到硬盘时,会按照utf-8(unicode transformation format)编码:
会将unicode的英文字符由原来的2Bytes变成1Bytes
会将unicode的中文字符由原来的2Bytes变成3Bytes
现在的计算机:
内存都是unicode
硬盘都是utf-8
数据由内存保存到硬盘:
1.内存中unicode格式的二进制数据 >>>> 编码(encode) >>>> 硬盘中utf-8格式的二进制数据
数据由硬盘读取到内存:
1.硬盘中utf-8格式的二进制数据 >>>> 解码(decode) >>>> 内存中unicode格式的二进制数据
保证不乱码在于,文本文件以什么编码编的就以什么编码解
# python2和python3的区别
python2: 将py文件按照文本文件读入解释器中默认使用ASCII码(因为在开发python2解释器时unicode还没有盛行)
python3: 将py文件按照文本文件读入解释器中默认使用utf-8
基于Python2解释器开发的软件,只要是中文,前面都需要加一个u,告诉python2解释器不要用默认的编码而用unicode,或则文件头指定的编码:
x = u'测试'
print type(x) # <type 'unicode'>
python3中中文默认就是unicode编码格式的二进制数
# 文件头
# coding: utf-8,告诉python解释器不要用默认的编码而用coding指定的编码
1.因为所有的编码都支持英文字符,所以文件头才能够正常生效
2.python2若有指定文件编码(coding)时默认使用ASCII存,若指定了文件编码,就用指定的文件编码来存
# 补充
pycharm终端用的是utf-8,windows终端用的是gbk
# 编码与解码
# 方式一:
x = '上'
res1 = x.encode('utf-8') # 将内存中unicode格式的二进制数据编码成可以存储和传输的utf-8格式的二进制数据
print(res1) # b'\xe4\xb8\x8a'
res2 = res1.decode('utf-8') # 将硬盘中utf-8格式的二进制数据解码成unicode格式的二进制数据
print(res2) # 上
# 方式二:
x = '上'
res1 = bytes(x, encoding='utf-8')
print(res1, type(res1)) # b'\xe4\xb8\x8a' <class 'bytes'>
res2 = str(res1, encoding='utf-8')
print(res2, type(res2)) # 上 <class 'str'>
文件处理
# python操作文件
f = open(r'E: \python学习\python视频教程\day07\代码\day07\a.txt', encoding='utf-8') # 打开文件,r取消转义
print(f) # <_io.TextIOWrapper name='E: \\python学习\\python视频教程\\day07\\代码\\day07\\a.txt' mode='r' encoding='utf-8'> f是文件对象
f.close() # 关闭文件
# 文件上下文操作,即自动f.close
with open(r'E: \python学习\python视频教程\day07\代码\day07\a.txt', encoding='utf-8') as f: # f仅仅是一个文件对象变量名
print(f)
# 打开多个文件
with open(r'E: \python学习\python视频教程\day07\代码\day07\a.txt') as f1,\
open(r'E: \python学习\python视频教程\day07\代码\day07\b.txt') as f2:
print(f1)
print(f2)
# 操作文件方式:
# t 文本文件,默认,需要指定encoding参数,如果不指定默认是操作系统编码
# b 二进制,不能指定encoding参数
with open(r'E: \python学习\python视频教程\day07\代码\day07\1.jpeg', mode='rb') as f:
print(f.read())
文件处理模式
r 只读模式(默认)
# mode参数可以不写,默认是rt
# r模式在打开文件时,如果文件不存在,直接报错
# 文件路径可以写相对路径,但是该文件必须与执行文件在同一层文件下
with open(r'a.txt', mode='r', encoding='utf-8') as f:
# mode关键字可以不写
with open(r'a.txt','r',encoding='utf-8') as f1:
# 读取文件要注意光标位置,当光标在文件末尾则读取不到文件内容
with open(r'E: \python学习\python视频教程\day07\代码\day07\a.txt', mode='r', encoding='utf-8') as f:
print(f.readable()) # True 是否可读
print(f.writable()) # False 是否可写
print(f.read()) # 将文件内容全部读出
print(f.readlines()) # 返回的是一个列表,列表中中的一个个元素对应文件中的一行行内容
for line in f: # f可以被for循环,每for循环一次读一行内容
print(line)
print(f.readline()) # 只读取文件一行内容
w 只写模式
# 1.当文件不存在的情况下,自动创建该文件
# 2.当文件存在的情况下,会先清空文件内容再写入
with open(r'xxx.txt', mode='w', encoding='utf-8') as f:
print(f.readable()) # False
print(f.writable()) # True
f.write('今天你翻车了~\n')
f.write('不不不,你没有翻~\r')
l = ['aaa~\n', 'bbb~\n', 'ccc~\n']
f.writelines(l)
# 上下等价
for i in l:
f.write(i)
a 追加模式
# 1.当文件不存在的情况下,自动创建该文件
# 2.当文件存在的情况下,不清空文件内容,文件光标会移动到文件最后
with open(r'yyy.txt', mode='a', encoding='utf-8') as f:
print(f.readable()) # False
print(f.writable()) # True
f.write('我是小尾巴\n')
r+
with open(r'test', mode='r+', encoding='utf-8') as f:
print(f.readable()) # True
print(f.writable()) # True
print(f.readline())
f.write('嘿嘿嘿') # 尾部写
w+
# w+,文件存在会清空
with open(r'test', mode='w+', encoding='utf-8') as f:
print(f.readable()) # True
print(f.writable()) # True
print(f.readline())
f.write('嘿嘿嘿')
a+
# 文件存在不会清空,写时尾部追加,光标会自动到文件尾部
with open(r'test', mode='a+', encoding='utf-8') as f:
print(f.readable()) # True
print(f.writable()) # True
print(f.readline()) # 光标会自动到文件尾部,所以读不到
f.write('嘿嘿嘿')
# 两种方式解码
with open(r'test', mode='r+b') as f:
print(f.readable()) # True
print(f.writable()) # True
res = f.read()
print(res.decode('utf-8'))
print(str(res, encoding='utf-8'))
文件光标移动
read()
# 在rt模式下,read内的数字表示的是字符的个数,其它情况表示的都是字节
with open(r'test', 'r', encoding='utf-8') as f:
print(f.read(3)) # 字符数
with open(r'test', 'rb') as f:
res = f.read(5) # 节数数
print(res)
print(res.decode('utf-8'))
seek()
# 文件内光标的移动
"""
f.seek(offset,whence) # f为文件对象
offset: 相对偏移量,光标移动的字节数
whence:
0: 参照文件的开头,t和b都可以使用
1: 参照光标所在的当前位置,只能在b模式下用
2: 参照文件的末尾,只能在b模式下使用
"""
# whence: 0
with open(r'test', 'rt', encoding='utf-8') as f:
f.seek(3, 0)
print(f.read(1))
f.seek(0, 0) # 光标移到开头
print(f.read(1))
with open(r'test', 'rb') as f:
f.seek(3, 0)
print(f.read(3).decode('utf-8'))
with open(r'test', 'r+', encoding='utf-8') as f:
f.seek(3, 0) # 字节数
f.write('过') # 不能插入只能替换
# whence: 1
with open(r'test', 'rb') as f:
print(f.read(3).decode('utf-8'))
f.seek(3, 1)
print(f.read(1))
# whence: 2
with open(r'test', 'rb') as f:
print(f.read().decode('utf-8'))
f.seek(-6, 2)
print(f.read().decode('utf-8'))
f.seek(0, 2) # 将光标移动到末尾
tell()
# 查看光标移动了多少位
with open(r'test', 'r', encoding='utf-8') as f:
print(f.read(3))
print(f.tell())
f.seek(3,0)
print(f.tell())
truncate()
with open(r'test01.txt', 'a', encoding='utf-8') as f:
f.truncate(10) # 保留0~10字节数,后面的全部删除(截断)
修改文件
with open(r'test', 'r+', encoding='utf-8') as f:
f.seek(3, 0)
f.write('y') # 这里往文本中间写入,不是插入而是覆盖
# 方式一:
"""
先将数据由硬盘读到内存(读文件)
在内存中完成修改(字符串的替换)
再覆盖原来的内容(写文件)
优点: 任意时间硬盘上只有一个文件,不会占用过多硬盘空间
缺点: 当文件过大的情况下,可能会造成内存溢出
"""
with open(r'test', 'r', encoding='utf-8') as f:
data = f.read()
print(type(data)) # <class 'str'>
with open(r'test', 'w', encoding='utf-8') as f:
res = data.replace('周三', '周五')
f.write(res)
# 方式二:
"""
创建一个新文件
循环读取老文件内容到内存进行修改,将修改好的内容写到新文件中
将老文件删除,将新文件的名字改成老文件名
优点: 内存中始终只有一行内容,不占内存
缺点: 在某一时刻硬盘上会同时存在两个文件
"""
import os
with open(r'test', 'r', encoding='utf-8') as read_f, \
open(r'test.swap', 'a', encoding='utf-8') as write_f:
for line in read_f:
new_line = line.replace('周五', '周末')
write_f.write(new_line)
os.remove('test') # 删除文件
os.rename('test.swap', 'test') # 重命名文件
名称空间
名称空间是什么?就是放名字的地方
详细解释: 存放的是变量名与变量值内存地址绑定关系的地方
要想访问一个变量的值,必须先去名称空间中拿到对应的名字,才能够访问变量的值
名称空间分类
1.内置名称空间: python解释器提前给你定义好的名字(已经存放到内置名称空间中了)
len、max、min...
2.全局名称空间: 文件级别的代码
x = 1
if 1 == 1 :
y = 2
while True:
z = 3
x、y、z都会放到全局名称空间
if、for、while无论嵌套多少层,它们内部所创建的名字都是全局名称空间的
3.局部名称空间: 函数体内创建的名字都属于局部名称空间,局部名称空间之间是无法直接访问的
def func():
username = 'jason'
func()
print(username) # NameError: name 'username' is not defined
名称空间生命周期
内置名称空间: python解释器一启动立马创建,关闭python解释器的时候内置名称空间自动销毁
全局名称空间: 运行py文件会自动创建,py文件程序运行结束自动销毁
局部名称空间: 函数被调用的时候自动创建,函数执行结束立即销毁(动态创建动态销毁)
名字查找顺序
"""
名称空间的查找顺序(******)
1.需要先确定你当前位置(大前提)
1.站在全局: 全局 >>> 内置
2.站在局部: 局部 >>> 全局 >>> 内置
2.函数在定义阶段变量名的查找顺序就已经固定了,不会因为函数调用位置变化而改变(******)
"""
x = 000
def f1():
x = 111
def f2():
def f3():
print(x) #此处x的查找顺序在函数定义阶段就已经固定了,函数f3没有定义x,而上层函数f2有定义,所以x的查找顺序固定为f2函数内,但由于先调用后定义则报错
f3()
x = 333
f2()
f1() # NameError: free variable 'x' referenced before assignment in enclosing scope
def func():
x = 1
def index():
print(x) # 由于函数index没有定义x,而上层函数func有定义x,则x的查找顺序固定为func函数内
return index
res = func()
x = 999
res() # 1
def func():
def index():
print(x) # 由于函数index和上层函数func都没有定义x,则x的查找顺序固定为去全局查找
return index
res = func()
x = 999
res() # 999
x=111
def outer():
def inner():
print(x)
return inner
f=outer()
def func():
x=333
f()
func() # 111
x=111
def outer():
def inner():
print(x)
x = 66666666
return inner
f=outer()
f() # UnboundLocalError: local variable 'x' referenced before assignment
名称空间作用域
# 全局作用域(全局有效): 内置名称空间、全局名称空间
# 局部作用域(局部有效): 局部名称空间
# global nonlocal
"""
global: 局部修改全局,如果想修改多个,逗号隔开
nonlocal: 局部修改局部,如果想修改多个,逗号隔开
"""
x = [] # 因为列表是可变类型,所以局部才能修改全局
def func():
x.append('abc')
func()
print(x) # ['abc']
# global 在局部修改全局的不可变数据类型
x = 1 # 不可变类型
username = 'jason'
def func():
global x,username # 修改全局变量,而不是创建局部名称空间
x = 999
username = 'egon'
func()
print(x) # 999
print(username) # egon
# nonlocal 局部修改局部
def func():
x = 1
def index():
nonlocal x
x = 2
index()
print(x)
func() # 2
三元表达式
"""
当某个条件成立做一件事,不成立做另外一件事
三元表达式的应用场景为只有两种可能的情况
三元表达式固定格式:
值1 if 条件 else 值2
条件成立返回值1
条件不成立返回值2
"""
# 比较两个数大小: 当x大时返回x,当y大时返回y
x = 99999
y = 88888
res = x if x > y else y
print(res)
a = False
de = a and "123" or "456"
print(de) # a为True返回123,a为False返回456
生成式
列表生成式
l = ['tank','nick','oscar','sean']
# 列表l内的每个元素加个后缀,例如 tank_dsb
# 方法一: for循环
l1 = []
for name in l:
l1.append('%s_dsb'%name)
# l1.append(name + '_dsb') # 不推荐使用
print(l1) # ['tank_dsb', 'nick_dsb', 'oscar_dsb', 'sean_dsb']
# 方法二: 列表生成式
l2 = ['%s_dsb'%name for name in l]
print(l2) # ['tank_dsb', 'nick_dsb', 'oscar_dsb', 'sean_dsb']
# 先for循环取出容器里每一个元素,然后交给if判断,条件成立才会交给for前面的代码,条件不成立则当前的元素直接舍弃
l = ['tank_dsb', 'nick_dsb', 'oscar_nb', 'sean_nb']
res = [name for name in l if name.endswith('_dsb')] # 不支持else
print(res) # ['tank_dsb', 'nick_dsb']
字典生成式
l1 = ['name','password','hobby']
l2 = ['jason','123','DBJ','egon']
d = {}
for i,j in enumerate(l1):
d[j] = l2[i]
print(d) # {'name': 'jason', 'password': '123', 'hobby': 'DBJ'}
# 字典生成式
l = ['jason','123','read']
d1 = {i: j for i,j in enumerate(l)}
print(d1) # {0: 'jason', 1: '123', 2: 'read'}
d2 = {i: j for i,j in enumerate(l) if j != '123'}
print(d2) # {0: 'jason', 2: 'read'}
集合生成式
res = {i for i in range(5) if i != 3}
print(res) # {0, 1, 2, 4}
迭代器和生成器
迭代器
可迭代对象
"""
什么是迭代器:
迭代: 更新换代(重复)的过程,每次迭代都必须基于上一次的结果
迭代器: 迭代取值的工具
迭代器提供了一种不依赖于索引取值的方式
可迭代对象: 内置有__iter__方法(用来生成迭代器对象)的都叫做可迭代对象
基本数据类型中,是可迭代对象的有: 符串、列表、元组、字典、集合、文件对象(执行内置的__iter__之后还是本身,文件对象本身就是迭代器对象)
"""
# 重复 + 每次迭代都是基于上一次的结果
s = 'hello'
n = 0
while n < len(s):
print(s[n])
n += 1
s = 'hello'
l = [1,2,34,]
t = (1,2,34)
d = {'name': 'jason'}
s1 = {1,2,3,4}
f = open('xxx.txt','w',encoding='utf-8')
print(s.__iter__()) # <str_iterator object at 0x0000025B84F18F70> 可简写为 print(iter(s))
print(f.__iter__()) # <_io.TextIOWrapper name='xxx.txt' mode='w' encoding='utf-8'>
迭代器对象
"""
迭代器对象:
1.内置有__iter__方法
2.内置有__next__方法
__iter__用来生成迭代器对象
__next__用来迭代器对象取值
可迭代对象: 内置有__iter__方法的
迭代器对象: 既内置有__iter__也内置有__next__方法
ps: 迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
迭代器对象无论执行多少次__iter__得到的还是迭代器对象本身(******)
迭代器取值的特点: 只能往后依次取,不能后退
"""
d = {'name': 'jason','password': '123','hobby': 'study'}
iter_d = d.__iter__() # 将可迭代对象d转换成迭代器对象
print(iter_d.__next__()) # name 迭代器对象的取值用__next__
print(iter_d.__next__()) # password
print(iter_d.__next__()) # hobby
print(iter_d.__next__()) # 取完了,报错StopIteration
# 异常处理
while True:
try:
print(iter_d.__next__())
except StopIteration:
break
f = open('xxx.txt','r',encoding='utf-8')
iter_f = f.__iter__() # 调用f的内置__iter__方法
print(iter_f is f) # True
print(f is f1.__iter__().__iter__().__iter__()) # True
f = open('xxx.txt','r',encoding='utf-8')
iter_f = f.__iter__()
print(iter_f.__next__())
print(iter_f.__next__())
print(iter_f.__next__())
for循环本质
"""
for循环的in关键,跟的是一个可迭代对象
for循环内部的本质:
1.将in后面的可迭代对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报这个错,自动结束循环
迭代取值:
优点:
1.不依赖于索引取值
2.内存中永远只占一份空间,不会导致内存溢出
缺点:
1.不能够获取指定元素
2.取完之后会报StopIteration错
"""
# map()、zip()等函数都是基于for循环的
l = [1,2,3]
res = map(lambda x: x+1,l)
print(res) # <map object at 0x00000133C0BA8FA0>
print(res.__next__()) # 2
print(res.__next__()) # 3
print(res.__next__()) # 4
l1 = [1,2,3,4]
l2 = ['a','b','c']
res = (zip(l1,l2))
print(res) # <zip object at 0x000001CB3DFD9440>
print(res.__next__()) # (1, 'a')
print(res.__next__()) # (2, 'b')
print(res.__next__()) # (3, 'c')
生成器
yield自定义生成器
"""
生成器: 用户自定义的迭代器,本质就是迭代器
yield:
1.提供一种自定义生成器的方式
2.将函数的运行状态暂停住
3.可以返回值
与return之间异同点:
相同点: 都可以返回值,并且都可以返回多个
不同点:
yield可以返回多次值,而return只能返回一次函数立即结束
yield还可以接受外部传入的值
"""
# 函数内如果有yield关键字,那么加括号执行函数时并不会触发函数体代码运行
def func1():
print('first')
yield
# yield后面跟的值就是调用迭代器的__next__方法得到的值
def func2():
yield 666
# yield既可以返回一个值也可以返回多个值,多个值按照元组的形式返回
def func3():
yield 666,777,888
def func4():
print('first')
yield 666
print('second')
yield 777
print('third')
g1 = func1() # 生成器初始化: 将函数变成迭代器
g2 = func2()
g3 = func3()
g4 = func4()
print(g1) # <generator object func at 0x0000028126371C10>
print(g1.__next__()) # first None
print(g2.__next__()) # 666
print(g3.__next__()) # (666, 777, 888)
print(g4.__next__()) # first 666
print(g4.__next__()) # second 777
print(g4.__next__()) # third StopIteration报错
def my_range(start,end,step=1):
while start < end:
yield start
start += step
for j in my_range(1,10,2):
print(j) # 1 3 5 7 9
# yield支持外界为其传参
def dog(name):
print('%s 准备开吃'%name)
while True:
food = yield
print('%s 吃了 %s'%(name,food))
g = dog('egon')
g.__next__() # egon 准备开吃 必须先将代码运行至yield,才能够为其传值
g.send('狗不理包子') # egon 吃了 狗不理包子 send即给yield传参并触发了__next__方法
g.send('饺子') # egon 吃了 饺子
生成器表达式
# 生成器表达式
res = (i for i in range(1,10) if i != 4)
print(res) # <generator object <genexpr> at 0x0000012307201C10>
print(res.__next__()) # 1
print(res.__next__()) # 2
print(res.__next__()) # 3
# 示例: 统计文件字符数
with open('xxx.txt','r',encoding='utf-8') as f:
g = (len(line) for line in f)
print(g.__next__())
print(g.__next__())
print(sum(g)) # 20
"""
第一次循环: g=(add(n,i) for i in test())
第二次循环: g=(add(n,i) for i in (add(n,i) for i in test()))
for i in (add(n,i) for i in test()): 会执行所有的生成器内部的代码
add(n,i)
"""
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [1,10]:
g=(add(n,i) for i in g)
print(list(g)) # [20, 21, 22, 23]
软件开发目录规范
项目名
-bin
--start.py 项目的启动文件(start.py也可以直接放在项目根目录下,变的只有BASE_DIR少一层路径)
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR)
from core import src
if __name__ == '__main__':
src.run()
"""
将项目根目录加到环境变量(sys.path)中
pycharm会自动将项目根目录加到环境变量(sys.path)中
若项目是被用户下载到他自己机器上,就必须在项目启动之前将项目根目录加到环境变量(sys.path)中
"""
-conf
--settings 项目的配置文件(不经常变动的变量)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# 拼接路径,注意不要手动拼接
LOG_PATH = os.path.join(BASE_DIR,'log')
print(LOG_PATH) # E: \python学习\python视频教程\day14\代码\day14\ATM\log
-core
--src.py 项目的核心逻辑文件,可能不止一个
-db
--数据相关
-lib
--common.py 项目所使用到的公共功能
-log
--项目的日志文件
Readme.txt 项目介绍
start.py (当start.py直接放在项目根目录下时)
import os
import sys
BASE_DIR = os.path.dirname(__file__)
sys.path.append(BASE_DIR)
from core import src
if __name__ == '__main__':
src.run()
- views 视图层
- interface 接口层
异常处理
"""
常见的错误类型:
NameError 名字错误
SyntaxError 语法错误
KeyError 键不存在
ValueError 值错误
IndexError 索引错误
报错种类:
1.语法错误
2.逻辑错误: 可以采用异常处理机制进行捕获
异常的结构: 1.异常的类型 2.异常的信息 3.异常的位置
异常处理使用:
在你认为可能会出现bug的代码块上方try一下,try内部的代码块越少越好
错误发生后会立刻停止运行代码,执行对应的except语句,没有对应的except则继续报错
Exception BaseException: 万能异常,所有异常类型都能被捕获到
异常处理语法:
try:
可能出错的代码
except 出错的类型1:
出错之后的处理机制
except 出错的类型2 as e: # 将异常的报错信息赋值给变量e
print(e)
出错之后的处理机制
...
else:
被检测的代码没有任何异常发生则走else
finally:
无论被检测的代码有没有异常发生都会在代码运行完毕之后执行finally
"""
# 关键字raise主动抛异常
if 'egon' == 'DSB':
pass
else:
raise TypeError('尽说大实话') # 主动抛出异常其实就是将异常类的对象打印出来,会走__str__方法
# assert 断言 预言 猜某个数据的状态,猜对了则不影响代码执行,猜错了则直接报错
l = [1,2,3]
assert len(l) < 0
print(l)
# 自定义异常
class MyError(BaseException):
def __init__(self,msg):
super().__init__()
self.msg=msg
def __str__(self):
return '<abc%sdef>' %self.msg
raise MyError('自定义异常') # __main__.MyError: <abc自定义异常def>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】