文章目录
补充
python中一起皆为对象,每个对象由:标识(identify)、类型(type)、value(值)组成
a = 3
print(a)-->3
print(id(3))-->153345687(地址)
print(id(a))-->153345687
同一运算符
- is 判断两个对象的地址(id)是否相同
- “==” 判断两个对象的值(value)是否相同
python为节省内存,设置了字符缓存机制:可以分为同一代码块内、不同代码块内两方面
(1)代码块的缓存机制:前提条件:在同一个代码块中
机制内容:python在执行同一个代码块的初始化对象的命令是,会检查是否其值已经存在,如果存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存在一个字典中,在遇到新的变量时,会现在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值。所以在你给出的例子中,文件执行时(同一个代码块)会把i1,i2两个变量指向同一个对象,满足缓存机制则他们在内存中只存在一个,即:id相同
适用对象:int(float),str,bool
对象的具体细则:(了解)
- int(float):任何数字在同一代码块下都会复用
- bool:True和False在字典中会以1,0方式存在,并且复用
- str:几乎鄋的字符串都符合缓存机制,具体规定如下(了解即可):
(2)小数据池
前提条件:在不同代码块中 -
- -5~256
python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象
- -5~256
-
- 一定规则的字符串
python将一定规则的字符串在字符串驻留池中创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象,而是使用字符串驻留池中创建好的对象
其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是讲-5~256的整数和一定规则的字符串,放在一个‘池’(容器或字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么它直接在这个‘池’中引用,言外之意,就是内存中只创建一个。
适用对象:int(float),str,bool
- 一定规则的字符串
对象的细则:
int:对于整数来说,小数据池的范围是-5~256,如果多个变量都是指向同一个(在这个范围内的数字),他们在内存中指向的都是一个内存地址
str:字符串要从下面这几个大方向讨论(了解即可!):
- 1,字符串的长度为0或者1,默认都采用了驻留机制(小数据池)。
- 2,字符串的长度>1,且只含有大小写字母,数字,下划线时,才会默认驻留。
- 3,用乘法得到的字符串(1) 乘数为1时:仅含大小写字母,数字,下划线,默认驻留。含其他字符,长度<=1,默认驻留。含其他字符,长度>1,默认驻留。(2)乘数>=2时:仅含大小写字母,数字,下划线,总长度<=20,默认驻留。
数据类型与变量
1.整数 1/200/-200
2.浮点数 1.235/0.36/-100.10
3.字符串’abc’
4.转义字符:
\
:'I\'m \"Fan\"!'
输出为I'm "Fan"!
\
可以转义很多字符
\n表示换行 \t表示制表符 \\表示\
有很多字符需要转义时:可以用 r''表示''内部的字符不转义
print(r'\\我是斜杠\\\')
'''...'''显示多行内容
print('''
,,,我要多行
。。显示''')
print(r'''
\t\t嵌套
\\\使用''')
- 布尔值(True/False请注意大小写)
布尔值可以参与常用的逻辑运算
True and True
True or False
not True/not 1>2
6.空值None
变量
变量在程序可以理解是一个名,我们可以给它赋予值(数据类型)
a =123 ; a= ‘abc’ ,这称a为动态语言
也可以为变量指定数据类型 如 int a=1
,称为静态语言
一旦赋予变量指定的数据类型,下面语句就是错误的。
a = "ABC"; // 错误:不能把字符串赋给整型变量
a =‘ABC’,=;//Python解释器干了两件事情
1.在内存中创建了一个’ABC’的字符串;
2.在内存中创建了一个名为a的变量,并把它指向’ABC’。
常量
常量即不变的量(但在py中并没有机制保护常量不被改变)
在Python中,通常用全部大写的变量名表示常量:
10//3=3
字符串和编码
字符串发展
美国人发明的ASCII
编码:
包括大小写英文字母、数字和一些符号
但处理中文,汉字中已经超出了ASCII编码的范围,一个中国制定了GB2312编码
Unicode应运而生,其将所有语言都涵盖进去
字母A用ASCII编码是十进制的65,二进制的01000001;
字符0用ASCII编码是十进制的48,二进制的00110000,注意字符’0’和整数0是不同的;
汉字中已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。
你可以猜测,如果把ASCII编码的A用Unicode编码,只需要在前面补0就可以,因此,A的Unicode编码是00000000 01000001。
但在有中文和英文同时存在时,Unicode编码就占据过大的存储空间,因此诞生了“可变长编码”的UTF-8编码
python的字符串
最新的python3版本中,字符串是以Unicode编码的,Python的字符串支持多语言
1.字符串
如print('中文yingwen')
2.对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:
如:
ord('A')//输出65
ord('中')//20013
chr(67)//C
也可以写成十六进制'\u4e2d\u6587'
//输出’中文‘
如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。 x = b'abc'
'ABC'.encode('ascii') b'ABC'
'中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87'
'中文'.encode('ascii')(出错)
b'ABC'.decode('ascii')
'ABC'
可见,1个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用1个字节。
在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。
可变字符串:
格式化:
在Python中,采用的格式化方式和C语言是一致的,用%实现,举例如下:
>>> print('Hello, %s' % 'world')
'Hello, world'
>>> print('Hi, %s, you have $%d.' % ('Michael', 1000000))
'Hi, Michael, you have $1000000.'
%s
永远起作用,它会把任何数据类型转换为字符串:
print('我%s岁了,我是%s生'% (25,True))
str.format()
s = 'my name is {} ,age {}'
s.format('hoho',18)
print(s)-->'my name is hoho ,age 18'
# 也可以指定索引
print('I am {1}, age {0}'.format(20,"lee"))
print("I am {name}, age {age}".format(name = "LEE",age = 25)
)
# 也可以指定关键字
'my name is {name},age is {age}'.format(name='hoho',age=19)
'my name is hoho,age is 19'
format()只支持字符串声明的格式化,而不支持变量
s = 'my name is {1} ,age {0}'
s.format(10,'hoho')
print(s)-->'my name is {1} ,age {0}' # 并没格式化
序列
序列中存储的是整数对象的地址,而不是整数对象的值,python中常见的序列有【字符串、列表、元组、字典】
list(列表)
list 是一种有序的集合,可以随时添加和删除其中的元素,可以存储任意数目、类型的数据集合。
列表创建
# 空
a = []
arry=['gog',25,'cog','hog']
cc = ['coc','kok',arry,'gg']
len(arry)--》4
cc[2][2]
# list()创建
a = list() # 创建一个空的列表对象
# list可以把任何可迭代的数据转换为列表
# range(start,end,step)
range(5,1,-1)-->5 4 3 2
a = list(range(5))-->a = [0,1,2,3,4]
a = list("123")--> a = ["1","2","3"]
# 列表推导式
a = [x*2 for x in range(5)]-->[0 1 4 6 8]
a = [x*2 for x in range(5) if x%4==0]-->[4 8]
# 二维列表
a = [[1,2,3],[2,3,4],50]
访问表内元素。arry[0]. 获取最后一个值arry[-1].访问超出则报错IndexError,如arry[10]
列表元素的增加和删除
python列表是大小可变的,可以随时增加和缩小
列表是顺序存储的,当列表增加和删除元素时,列表会自动进行内存管理,大大减少了程序员的负担。但这个特点涉及列表元素的大量移动,效率较低。除非必要,我们一般只在列表的尾部添加元素或删除元素,这会大大提高列表的操作效率
# append()
a = [20,30]
a.append(50)-->a = [20,30,50]
插入到指定的位置:`cc.insert(i,'lol')`#i是正数时插入到指定位置,i为负数时,插入到指定位置的前面
# 删除
a = [10,20,30]
1、del a[0]
2、a.pop(0)
3、a.remove(20) # 删除第一个20,没有20会报错
# 访问
查找位置 a.index(20) 查找第一个20,index(value,[start,end])在指定范围查找
a[1]-->20
cout 统计出现的个数
列表的方法:
tuple(元组)
另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改(指向永远不变)
如果元组里有list,可以对list进行改变,但是元组的指向还是list
# 可通过(),tuple(可迭代对象),zip()创建元组
t=('toe',[25,23,'bb'],'bob')
t = tuple(range(5))
a = ("a","b")
b = ("c","d")
zip(a,b)-->[("a","b"),("c","d")](返回的是列表)
# 推导式
s = [x*2 for x in range(4)] #s是一个迭代器对象
s._next_()-->0
s._next_()-->2
也可以 a = tuple(s)
1.不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
2.tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来
如arry=('gog',25,'cog','hog')
,arry这个元组就不能再改变,它也没有append(),insert()
这样的方法。其他元素获取的方法和list相同。
需要注意的是:
如果要定义一个只有一个元素的元组,应该写t=(1,).加逗号消除歧义(这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号)。
且定义一个空的tuple是t=()
使用dict和set
字典
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度
如果用list列表实现:
names = ['Michael', 'Bob', 'Tracy']
scores = [95, 75, 85]
要查Bob的成绩,就需要找到names列表中Bob的位置,然后再去scores列表中找对应位置的元素。这样,若了列表很长,查询速度就很慢(和链表相似)。
而dic:
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
zip()创建字典生成的还是字典
查找速度就很快,相当于在字典里的索引,直接找索引,然后根据索引直接找到对应的位置,而不用一个一个找。
给定一个名字,比如’Michael’,dict在内部就可以直接计算出Michael对应的存放成绩的“页码”,也就是95这个数字存放的内存地址,直接取出来,所以速度非常快。
这就是key-value
存储方式。
在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value。
#增 //一个key只能对应一个value
d["Adam"] = 67
#删 //对应的value也会被删除。
d.pop(key)
#改
d["Michael"] = 100
#查
1.in 判断key是否存在`"aa" in d` 存在就是True
如:print('Michael' in d)--->True
2. d.get('a',-1),如果不存在就返回-1
但是:dict内部存放的顺序和key放入的顺序是没有关系的。
和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
而list相反:
查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
正确使用
dict
非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这个通过key计算位置的算法称为哈希算法(Hash)
字典核心底层原理
序列解包
x,y,z = (20,30,40)-->x = 20,y=30,z = 40
# 序列解包用于字典时,默认是对键进行操作的
a = {"name":"lee","age":18}
name,age = a-->name = "name"
name,age = a.items()-->name = {"name":"lee"}
集合set
set也是一组key集合,但是不存储value.同dic,key也不能重复。
#定义 创建一个set,需要提供一个list作为输入集合
s = set([1,2,3])
print(s) -----{1,2,3}
#显示的{1, 2, 3}只是告诉你这个set内部有1,2,3这3个元素,显示的顺序也不表示set是有序的
#并且重复的元素在set中自动被过滤
s =set([11,22,33,33,33,22])
print(s)------{11,22,33}
#增:
s.add(key)# 增加在前面
#删
s.remove(key)
set可以看成数学意义上的无序和无重复元素的集合,因此可以执行交/并操作。
s &s1 s | s1
set和dict的唯一区别仅在于没有存储对应的value
不可变对象
字符串、整数等都是不可变的,而列表list是可变的
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
cc =(1,2,[1,2,3])
d[cc] = 'K'
会出错cc=(1,2,3)改为元组就不会出错
**列表:**
如:b =['a','b','c']
如果有:b[0]='m'
列表b变成了 b =['m','b','c']#是可变的
**字符串str**
a='abc'
有a.replace('a',m)
print(a)#这时还是输出abc,a并没有变化
但H=a.replace('a',m)
print(H)#就输出了mbc
因此可以这样:
d = {'gog':25,'cog':'hog'}
a = 'abc'
d[a] = 'K'
print(d[a])--->'K'
'实际上K是指向了'abc''
a = 12
b = 'abc'
print(d[a])--->报错KeyError: 12
print(d['abc'])--->'K'
print(d[b])--->'K'
> a是变量,而'abc'才是字符串对象!有些时候,我们经常说,对象a的内容是'abc',
> 但其实是指,a本身是一个变量,它指向的对象的内容是'abc'
> replace是替换了一个字符并返回给一个变量,相当于函数
当我们调用
a.replace('a', 'A')
时,实际上调用方法replace
是作用在字符串对象'abc'
上的,而这个方法虽然名字叫replace
,但却没有改变字符串'abc'
的内容。相反,replace
方法创建了一个新字符串'Abc'
并返回,如果我们用变量b
指向该新字符串,就容易理解了,变量a
仍指向原有的字符串'abc'
,但变量b
却指向新字符串'Abc'
了:
条件判断
条件判断内容和C相似。
需要注意的是Python的缩进规则
,同属一个判断条件内的,缩进应该相同
(根据条件以此判断)如:
a=35;
b=30;
if a > 50:
print('a =',a)
print('a大于50')
elif a > b and a>30:
print('a =',a)
print('a大于 %d,小于50' %(b))
else:
print('a 小于 %d' %(b))#''后没有逗号,直接跟% (b)
也可以时单个变量:
if x:
print('True')
> x是`非零数值`、`非空字符串`、`非空list`等,就判断为`True`,否则为`False`
带有输入(`input()`)互动的判断:
s = input('birth: ')
birth = int(s) #输入应该是数字,如果不加这一句,上一步输入就默认是str类型的,就会报错
#当然,如果这个时候输入字符,如abc,int()函数发现一个字符串并不是合法的数字时就会报错
if birth < 2000:
print('00前')
else:
print('00后')
循环
与C不同python的循环语句有点特殊。
- 可以用for…in循环,依次把list或tuple中的每个元素迭代出来
names = ['Michael', 'Bob', 'Tracy']
for i in names:# for 迭代变量 in 字符串|列表|元组|字典|集合
print(i)
> **格式中,迭代变量用于存放从序列类型变量中读取出来的元素,所以一般不会在循环中对迭代变量手动值;代码块指的是具有相同缩进格式的多行代码。
> 所以for i in ...循环就是把每个元素代入变量i,然后执行缩进块的语句**
那么计算1-1000之间的和就可以这样计算:
sum = 0
for x in range(1001):# range(4) 0,1,2,3
sum = sum + x
print(sum)
- while循环
只要条件满足,就不断循环,条件不满足时退出循环
#1-100的和
sum = 0
n = 100
while n > 0:
sum = sum + n
n = n - 1
print(sum)
> 循环内部变量`n`不断自减,直到变为-1时,不再满足`while`条件,循环退出。
break
break
语句可以提前退出循环
n = 1
while n <= 100:
if n > 10: # 当n = 11时,条件满足,执行break语句
break # break语句会结束当前循环
print(n)
n = n + 1
print('END')
continue
通过continue语句,跳过当前的这次循环,直接开始下一次循环。
n = 0
while n < 10:
n = n + 1
if n % 2 == 0: # 如果n是偶数,执行continue语句
continue # continue语句会直接继续下一轮循环,后续的print()语句不会执行
print(n)
要特别注意,不要滥用break和continue语句。break和continue会造成代码执行逻辑分叉过多,容易出错。大多数循环并不需要用到break和continue语句,上面的两个例子,都可以通过改写循环条件或者修改循环逻辑,去掉break和continue语句。