day2
变量的创建与id
例1:name = 'iruance'
首先,当我们定义了一个变量name = ‘iruance’的时候,在内存中其实是做了这样一件事:
程序开辟了一块内存空间,将‘iruance’存储进去,再让变量名name指向‘iruance’所在的内存地址。如下图所示:

例2:两个变量名一个值
提问:当我执行下面这段代码的时候,程序是怎么处理的呢?
我们猜想会有两种可能:
第一种情况:程序分别在内存中开辟了两块儿空间来存储‘iruance’这个值,并且让name1和name2指向这两个值。如下左图
第二种情况:由于两个值内容一致,所以程序只开辟一块儿空间存储‘iruance’,并让name1和name2只想着个值。如下右图
提问:大家来猜测一下会是哪种情况?

其实上面的两种猜想都是对的。正常情况下字符串在内存里就是如我们猜想的第一种情况一样,每一次创建一个变量都会在内存中申请一块儿空间。
但是,python认为一些“看起来像python标识符的字符”和小整数字在开发中是常用的,因此出于节省内存的角度思考,对于这部分字符串和数字做出了优化[-5,257),python解释器会由于要定义的新变量内容与之前定义过的变量内容相同而不让这部分内容占用新的内存空间。
我们如何证明我们的想法呢?
python为我们提供了一个id()方法,可以查看一个变量的内存地址。
name1 = 'iruance' name2 = 'iruance' print(id(name1)) print(id(name2))
执行完这段代码就基本验证了我们的思想,由于‘iruabce’是一个简单的字符串,因此python解释器做了优化,内存里只有一个‘iruance’,name1和name2都指向同一块儿内存地址。
例3:一个变量名2个值
提问:如果像下面这样写自己的代码,最终打印name会得到什么结果?
name = 'iruance' name = 'banzhang' print(name)
我想大家的答案是一致的,name此时应该是‘banzhang’,当我们在程序中对变量进行重复赋值时,就是对一个变量进行修改.
代码解读:
程序先申请了一块内存空间来存储‘iruance’,让name变量名指向这块内存空间
读到name=‘banzhang’之后又申请了另一块内存空间来存储‘banzhang’,并让原本指向‘iruance’内存的链接断开,让name再指向‘banzhang’。
如下图所示:

例4:变量的赋值与修改
提问:如果像下面这样写自己的代码,最终打印name1和name2会分别得到什么结果?
name1 = 'iruance' name2 = name1 name1 = 'banzhang' print(name1,name2)
这里大家就会产生一些争论了,先执行一下给大家看。

要想知道上面问题的结果是为什么,首先要了解在内存中两个变量的存储情况。

从上面的示意图中我们可以知道,当执行name2=name1这句话的时候,事实上是让name2指向了‘iruance’所在的内存地址。
修改name1的值,相当于断开了name1到‘iruance’的链接,重新建立name1和‘banzhang’之间的链接。在这个过程中,始终没有影响到name2和‘iruance‘之间的关系,因此name2还是‘iruance’,而name1变成了‘banzhang’。
赋值运算
以下假设变量:a=10,b=20
# a += 1 # a =a +1 # a -= 1 # a =a-1 # # a = 1 # b = 2 # a += b # a = a+b =1+2=3 # b += a # b = b+a =2+3=5 # print(a, b) # # a = 10 # b = 6 # a %= b # print(a)
逻辑运算
and 表示并且 两个都为真,才为真, 一真一假则为假,两个都为假则为假
or 表示或 两个都为真则为真,两个都为假,则为假,一真一假则为真
not 表示非(相反) not True 为 False not False 为 True
整个逻辑运算中优先级
括号()的优先级最高 not and or
# and 表示并且 # True and True == True # True and False == False # or 表示或者 # True or True == True # True or False == True # False or True == True # False or False == False # not 表示相反 # not True == False # not False == True # a = 10 # b = 5 # a < b and b > 3 # False and True == False # a<b or b>3 # False or True == True # not a<b # not False == True # 整个逻辑运算中优先级 # 括号的优先级最高 # not # and # or # not a<b or a<b and b>3 # True or False and True # False or False # print(not a<b or a<b and b>3) # 坑 # print(1 or 5) # print(0 or 5) # a or b # if a is True 结果是a 否则结果是b print(1 and 5) print(0 and 5) # and 和 or 刚好相反 # 3>4 and 5<7 or 8 and not False # False and True or 8 and True # False or True
练习题一起完成一下
# 3>4 or 4<3 and 1==1 # 1<2 and 3<4 or 1>2 # 2>1 and 3<4 or 4>5 and 2<1 # 1>2 and 3<4 or 4>5 and 2<1 # 1>2 and 3<4 or 4>5 and 2>1 or 9<8 # 1>1 and 3<4 or 4>5 and 2>1 and 9>8 or not 7<6 # True # print(1>2 and 3<4 or 4>5 and 2>1 or 9<8) # print(1>2 and 3<4 or 4>5 and 2<1) # print(2>1 and 3<4 or 4>5 and 2<1) # print(3>4 or 4<3 and 1==1) # print(1<2 and 3<4 or 1>2) # print(1>1 and 3<4 or 4>5 and 2>1 and 9>8 or not 7<6 )
身份运算

身份运算符:判断的是两个变量内存地址
如果两个变量的内存地址相等,值一定相等
a = 1 b = 1 print(a==b) print(id(a)) print(id(b)) print(a is b) print(a is not b )
二进制
# 计算机能够看懂的语言 01 # 二进制 # 0101010101 # 二进制 --> 十进制 # 0 --> 0 # 1 --> 1 # 10 ==> 2 # 11 -->3 # 100 -->4 # 101 -->5 # 110 --> 6 # 111 -->7 # 1000 -->8
# 八进制 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 10 -->8 # 11--> 9
# 十六进制 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # A # B # C # D # E # F # 10 -->16 # 11 -- 17
字符编码
通过上一节讲的二进制的知识,大家已经知道计算机只认识二进制,生活中的数字要想让计算机理解就必须转换成二进制。十进制到二进制的转换只能解决计算机理解数字的问题,那么文字要怎么让计算机理解呢?
于是我们就选择了一种曲线救国的方式,既然数字可以转换成十进制,我们只要想办法把文字转换成数字,这样文字不就可以表示成二进制了么?

可是文字应该怎么转换成数字呢?就是强制转换
我们自己强行约定了一个表,把文字和数字对应上,这张表就相当于翻译,我们可以拿着一个数字来对比对应表找到相应的文字,反之亦然。
ASCII码
# 十进制转换成ascii ,使用chr()函数 print(chr(65)) # ascii 转为十进制,使用ord函数 print(ord('A'))
假如我们就已经有这么一张表了

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。
由于计算机是美国人发明的,因此,最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母 A的编码是65,小写字母 z的编码是122。后128个称为扩展ASCII码。
那现在我们就知道了上面的字母符号和数字对应的表是早就存在的。那么根据现在有的一些十进制,我们就可以转换成二进制的编码串。
比如
提问:假如我们要打印两个空格一个对勾 写作二进制就应该是 0011111011但是 但是问题来了,我们怎么知道从哪儿到哪儿是一个字符呢?
正是由于这些字符串长的长,短的短,写在一起让我们难以分清每一个字符的起止位置,所以聪明的人类就想出了一个解决办法,既然一共就这255个字符,那最长的也不过是11111111八位,不如我们就把所有的二进制都转换成8位的,不足的用0来替换。
这样一来,刚刚的两个空格一个对勾就写作000000000000000011111011,读取的时候只要每次读8个字符就能知道每个字符的二进制值啦。
在这里,每一位0或者1所占的空间单位为bit(比特),这是计算机中最小的表示单位
每8个bit组成一个字符,这是计算机中最小的存储单位(毕竟你是没有办法存储半个字符的)orz~
要不要举例子说单位?就像我们形容长度会有厘米、分米、米之分,在计算机里也有自己的计量数据大小的单位
人民币的例子:给了你好多钱,假如没有万-十万
bit 位,计算机中最小的表示单位 8bit = 1bytes 字节,最小的存储单位,1bytes缩写为1B 1KB=1024B 1MB=1024KB 1GB=1024MB 1TB=1024GB 1PB=1024TB 1EB=1024PB 1ZB=1024EB 1YB=1024ZB 1BB=1024YB
提问:学完ascii码,作为一个英文程序员来说,基本圆满了。但是作为一个中国程序员,你是不是觉得少了点儿什么?
GBK和GB2312
显然,对于我们来说能在计算机中显示中文字符是至关重要的,然而刚学习的ASCII表里连一个偏旁部首也没有。所以我们还需要一张关于中文和数字对应的关系表。之前我们已经看到了,一个字节只能最多表示256个字符,要处理中文显然一个字节是不够的,所以我们需要采用两个字节来表示,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。
你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,
各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
支持 中文,英文,数字,符号 英文 8位 1个字节 中文 16位 二个字节
Unicode
因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
现在,捋一捋ASCII编码和Unicode编码的区别:
ASCII编码是1个字节,而Unicode编码通常是2个字节。
字母A用ASCII编码是十进制的65,二进制的01000001;
字符0用ASCII编码是十进制的48,二进制的00110000;
汉字“中”已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。
你可以猜测,如果把ASCII编码的A用Unicode编码,只需要在前面补0就可以,因此,A的Unicode编码是00000000 01000001。新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
万国码 支持 中文,英文,数字,符号 英文 32 位 四个字节 中文 32位 四个字节
UTF-8
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:
| 字符 | ASCII | Unicode | UTF-8 |
| A | 01000001 | 00000000 01000001 | 01000001 |
| 中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
搞清楚了ASCII、Unicode和UTF-8的关系,我们就可以总结一下现在计算机系统通用的字符编码工作方式:
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。
文件存取编码转换图
utf-8 可变长的编码 -- 节省空间 如果是英文字母 8位 1字节 如果是欧洲文字 16位 2字节 中国文字 24位 3字节
编码的转换
# s = '你好,老弟' # print(s.encode('utf-8')) # unicode -->utf-8 # 转成16进制的字节 # 一般只有往文件中写入数据或往网络上传输时转为字节 # b = b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe8\x80\x81\xe5\xbc\x9f' # print(b.decode('utf-8')) # s = '你好,老弟' # print(s.encode('gbk')) # unicode -->utf-8 # 转成16进制的字节 # # 一般只有往文件中写入数据或往网络上传输时转为字节 # b = b'\xc4\xe3\xba\xc3,\xc0\xcf\xb5\xdc' # print(b.decode('gbk'))
常用编码介绍一览表
| 编码 | 制定时间 | 作用 | 所占字节数 |
| ASCII | 1967年 | 表示英语及西欧语言 | 8bit/1bytes |
| GB2312 | 1980年 | 国家简体中文字符集,兼容ASCII | 2bytes |
| Unicode | 1991年 | 国际标准组织统一标准字符集 | 2bytes |
| GBK | 1995年 | GB2312的扩展字符集,支持繁体字,兼容GB2312 | 2bytes |
| UTF-8 | 1992年 | 不定长编码 | 1-3bytes |
字符串
把字符连成串. 在python中 用单引号, 双引号 , 三引号引起来的内容被称为字符串.
切片和索引
- 索引. 索引就是下标. 切记, 下标从0开始
- 切片, 我们可以使 用下标来截取部分字符串的内容
-
-
语法: str[start: end]
规则: 顾头不顾腚, 从start开始截取. 截取到end位置. 但不包括end
-
-

跳着截取

步 长: 如果是整数, 则从左往右取. 如果是负数. 则从右往左取. 默认是1切片语法:
切片语法:
str[start:end:step] start: 起始位置
end: 结束位置
step:步 长
字符串的相关操作方法
切记, 字符串是不可变的对象, 所以任何操作对原字符串是不会有任何影响的
大小写转来转去
s = 'iruance'
s1 = s.capitalize() # 首字母大写
print(s1)
s2 = s.upper() # 全部转为大写
print(s2)
s3 = s.lower() # 全部转为小写
print(s3)
切来切去

注意有坑:

格式化输出
查找

条件判断

6. 计算字符串的长度

注意: len()是python的内置函数. 所以访问 方式也不 一样. 你就记着len()和print() 一样就行了
7. 迭代
我们可以使 用for循环来遍历(获取)字符串中的每 一个字符语法:
for 变量 in 可迭代对象:
pass
可迭代对象: 可以 一个 ,一个往外取值的对象

字符串作业
1.请输出 name 变量对应的值中 "e" 所在索引位置? name = "aleX leNb" 3.使用for循环对s ='asdsf'进行循环、分别打印字符串中的每个元素 4、使用for循环对s ='asdsf'进行循环、每次打印的内容都是'asdsf' 5.使用for循环对s ='asdsf'进行循环、每次打印的内容加上'sb' 6、使用for循环对s='321'进行循环、打印内容依次是:"倒计时3秒"、"倒计时2秒"、"倒计时1秒"、出发 7.实现一个整数加法计算器(两个数相加) #如 content =input(请输入内容:)用户输入:5+9然后进行分割再进行计算 8. 计算输入的内容是几位整数(已个位为单位)# content = input("请输⼊内容:") # 如fhdau234slfh98769fjdba 9、1 - 2 + 3 - 4 ... + 99 去掉88 10.输入一个字符串,要求判断这个字符串中大写字母、小写字母、数字, 共出现了多少次,并输出出来
列表
列表的介绍
列表是python的基础数据类型之 一 ,其他编程语言也有类似的数据类型. 比如JS中的数组, java中的数组等等. 它是以[ ]括起来, 每个元素 用' , '隔开 而且可以存放各种数据类型:

列表相比于字符串. 不仅可以存放不同的数据类型. 而且可以存放大量的数据. 32位python可以存放: 536870912个元素, 64位可以存放: 1152921504606846975个元素. 而且列表是有序的(按照你保存的顺序),有索引, 可以切片方便取值.
2.2 列表的索引和切片
列表和字符串 一样也拥有索引:

列表的切片:
顾头不顾尾
print(lst[1:3]) print(lst[:2]) print(lst[2:]) print(lst[:]) print(lst[-1:-3]) # 倒着切 print(lst[-3:-1]) print(lst[-3:-1:1]) # start:end:step print(lst[-1:-3:-1]) print(lst[::-1]) print(lst[::2]) print(lst[1::3])
列表的增删改查
增, 注意, list和str是不 一样的. lst可以发生改变. 所以直接就在原来的对象上进行了操作
append,insert,extend

注意:
一般情况下不要用insert做操作
删除
pop, remove, clear, del
lst = ['李嘉诚', '许家印', '王石', '张三'] lst.pop() # 默认删除最后一个元素 print(lst) el = lst.pop(0) # 根据索引删除元素 print(el) print(lst) lst.remove('许家印') print(lst) lst.remove('哈哈哈') # 删除不存在的元素会报错 lst.clear() # 清空列表 print(lst) del lst[1:3] print(lst)
修改
索引切片修改
lst = ['周润发', '周杰伦', '周星驰', '郭德纲', '尼古拉斯赵四'] lst[2] = '喜剧之王' # 根据索引修改值 print(lst) lst[1:4] = ['马化腾','马云'] print(lst) lst[1:4:3] = ['刘强东','奶茶妹'] # ValueError,如果步长不是1,切片修改注意元素个数 print(lst)
其他操作
lst = ['张三', '李四', '王五', '张三'] c = lst.count('张三') print(c) lst1 = [1, 11, 33, 66, 2] lst1.sort() # 排序 默认升序 print(lst1) lst1.sort(reverse=True) # 降序 print(lst1) lst =['周润发', '周杰伦', '周星驰', '郭德纲', '尼古拉斯赵四'] print(lst) print(lst.reverse()) # 反转 print(lst)
列表的嵌套

列表的拷贝
lst = ['龚sir', '李sir', '隔壁老王', '神奇的张三', '尼古拉斯赵四'] lst2 = lst[1:3]
lst3 = lst[:] print(lst3 == lst) print(id(lst1)) print(id(lst2))
深浅拷贝
浅拷贝:我并不是在内存生成完全隔离的数据,只有第一层隔离了数据,如果非第一层内存地址中的数据发生了变化,我所有拷贝的列表都共享这一变化
浅拷贝 # l = ['wind', 123, True, ['张三', '123456', '18'], ['李四', '10086', 30]] # l2 = l[:] # l3 = l.copy() # # l2.append('hello,world') # print(l) # print(l2) # print(l3) # # l2[3].append('你好啊') # print(l) # print(l2) # print(l3)

深拷贝
全部数据/结构都进行复制,连内存地址都拷贝了,一般不推荐,浪费内存
# import copy # # l2 = copy.deepcopy(l) # l2[3].append('hello world') # print(l) # print(l2)
列表在内存中如何存储
l = ['李sir', '123456', '666'] l2 = ['龚sir', '10086', 18] lst = [] lst.append(l) lst.append(l2) print(lst) # 修改李sir的年龄 -->22 改回小鲜肉 lisir = lst[0] # 拿到的实际是它的内存地址 lisir[2] = 22 print(lisir) print(lst)

for循环
while 循环和for循环的区别
while循环是根据条件来的,所以结束循环的次数是不固定的
for循环 循环的次数永远等于你循环的那个列表/其他数据类型的长度
lst = [3, 5, 6, 78, 9, 2, 3] # 打印这个列表中的所有元素 n = 0 while n < len(lst): print(lst[n]) n += 1 # for 循环 for n in lst: print(n) for i in lst: if i ==9: break # continue print(i)
练习
l = [['wind', '222'], ['老王', '666'], ['张三', '123456']]
# 让用户输入用户名和密码
# 只要用户名和密码对上了L中的值,显示登录成功,并退出循环
# 否则,显示登录失败
l = [['wind', '222'], ['老王', '666'], ['张三', '123456']] username = input('请输入用户名') pwd = input('请输入密码') for i in l: # ['wind', '222'], ['老王', '666'] if username == i[0] and pwd == i[1]: print('登录成功') break else: # 当for循环执行结束,并且在执行过程中没有被break,执行else中的代码 print('登录失败')
练习题
1、请用代码实现:利用下划线将列表的每一个元素拼接成字符串,li=['周润发','周杰伦', '周星驰']
2、查找列表中元素,移除每个元素的空格,并查找以a或A开头并且以c结尾的所有元素。
li = ["alec", " aric", "wind", "Tony", "rain"]
3、写代码,有如下列表,按照要求实现每一个功能
li=['wind', 'eric', 'rain']
- 计算列表长度并输出
- 列表中追加元素“seven”,并输出添加后的列表
- 请在列表的第1个位置插入元素“Tony”,并输出添加后的列表
- 请修改列表第2个位置的元素为“Kelly”,并输出修改后的列表
- 请删除列表中的元素“eric”,并输出修改后的列表
- 请删除列表中的第2个元素,并输出删除的元素的值和删除元素后的列表
- 请删除列表中的第3个元素,并输出删除元素后的列表
- 请删除列表中的第2至4个元素,并输出删除元素后的列表
- 请将列表所有的元素反转,并输出反转后的列表
- 请使用for、len、range输出列表的索引
- 请使用for循环输出列表的所有元素
4、写代码,有如下列表,请按照功能要求实现每一个功能
li = ["hello", 'seven', ["mon", ["h", "kelly"], 'all'], 123, 446]
- 请根据索引输出“Kelly”
- 请使用索引找到’all’元素并将其修改为“ALL”,如:li[0][1][9]…
5、有如下变量,请实现要求的功能
tu = ("wind", [11, 22, {"k1": 'v1', "k2": ["age", "name"], "k3": (11,22,33)}, 44])
- 讲述元组的特性
- 请问tu变量中的第一个元素“wind”是否可被修改?
- 请问tu变量中的”k2”对应的值是什么类型?是否可以被修改?如果可以,请在其中添加一个元素“Seven”
- 请问tu变量中的”k3”对应的值是什么类型?是否可以被修改?如果可以,请在其中添加一个元素“Seven”
6、转换
- 将字符串s = “wind”转换成列表
- 将字符串s = “wind”转换成元祖
- 将列表li = [“wind”, “seven”]转换成元组
- 将元组tu = (‘wind’, “seven”)转换成列表
- 将列表li = [“wind”, “seven”]转换成字典
7、元素分类
有如下值集合[11,22,33,44,55,66,77,88,99,90],将所有大于66的值保存至字典的第一个key中,将小于66的值保存至第二个key的值中。
即:{‘k1’:大于66的所有值, ‘k2’:小于66的所有值}。(编程题)
8、在不改变列表数据结构的情况下找最大值li = [1,3,2,7,6,23,41,243,33,85,56]。(编程题)
9、利用for循环和range输出9 * 9乘法表 。(编程题)
作业
一、利用字典实现用户认证功能,字典格式如下
userinfo = {'wind':'wind123','admin':'666'}
要求:
1)用户可以选择操作,登录或者注册
2)如果是登录,要求输入正确的用户名和密码,超过三次则登录失败
3)如果是注册,要求用户输入用户名,密码,确认密码,完成注册之后进入用户登录功能
二、三级菜单。有字典如下:
menu = { '北京': { '海淀': { '五道口': { 'soho': {}, '网易': {}, 'google': {} }, '中关村': { '爱奇艺': {}, '汽车之家': {}, 'youku': {}, }, '上地': { '百度': {}, }, }, '昌平': { '沙河': { '爱软测': {}, '北航': {}, }, '天通苑': {}, '回龙观': {}, }, '朝阳': {}, '东城': {}, }, '上海': { '闵行': { "人民广场": { '炸鸡店': {} } }, '闸北': { '火车战': { '携程': {} } }, '浦东': {}, }, '山东': {}, }
要求用户根据输入的内容进入下一级菜单,可以返回上一级,也可以直接退出



浙公网安备 33010602011771号