本节内容
- 元组操作
- 字典操作
- 文件操作的初步认识
一、元组
1.元组其实跟列表差不多,也是存储一组数据的,只是它一旦创建,便不能再修改的。
例如:
names =("zhangsan","lisi","wangwu")
它只有两个方法,一个是count,一个是index,同样它也可以切片。
names = ("zhangsan","lisi","wangwu","zhangsan")
print(names.count("zhangsan"))
print(names.index("lisi"))
print(names[1:])
print(names[:2])
.
.
.
二、字典的操作
字典是一系列的键-值对。每个键都与一个值相关联,你可以使用键来访问与之对应的值。与键相关联的值可以是数字、字符串、列表乃至字典。
事实上可以将任何python对象用作字典的值。
info = { "name1":"zhangsan",
"name2":"lisi",
"name3":"wangwu" }
字典的特性:
无序的
key必须是唯一的,所以天生去重
1、访问字典中的值
print(info["name2"])
判断一个key在不在字典中
print("names1" in info)
返回True存在 False 不存在
print(info.get("names1"))
存在返回值,不存在返回None print(info.get("names","panglicai"))
可以跟个参数“panglicai”,当不存在是可以打印panglicai
2、增加键-值对
info["names4"] = "zhaoliu"
info["names5"] = ["zhaoliu",22]
info["names6"] = {"names":"zhaoliu","age":22}
3、修改一个键-值对
info["names5"][1] = 33
info["names6"][names] = "plc"
4、删除
info.pop()
info.pop("names1") 删除后会返回删除的值
info.pop("names7")删除不存在的会报错
info.pop("names7","mei")当添加参数后,删除不存在的会显示指定的参数mei而不会再报错
del删除后不会返回删除的值
del info["names2"] 删除后的键-值对会永远消失
5、fromkeys()
names = ["alex","jack","rain"]
print(dict.fromkeys(names,0))
>>{'alex': 0, 'jack': 0, 'rain': 0}
会把names列表中的每个元素当做key 然后把指定的参数0当做value
相当于这三个key值指向的都是同一个value可以通过id看内存的地址的方法
print(id(n1["alex"]),id(n1["rain"]))
>> 1512064640 1512064640
当指定的参数是字符串或数字时,可以修改其中的值
n1 = dict.fromkeys(names,0)
n1["jack"] = 2
print(n1)
>>{'alex': 0, 'jack': 2, 'rain': 0}
可以看到只有jack对应的值变了相当于(a=10 b=a a =11 b还是10的原理一样)
当指定的参数是一个列表时修改其中的一个值,其字典中的值都会变
n1 = dict.fromkeys(names,[1,2,3])
n1["jack"][1] = 4
print(n1)
>>{'alex': [1, 4, 3], 'jack': [1, 4, 3], 'rain': [1, 4, 3]}
结果会把所有key相关联的value都改了
因为当其中一个列表的值变化时它不会开辟一块新空间来存储,而是在原列表中直接修改,
并且原来的指向关系也没有发生变化,所以列表中的其中一个元素发生变化,
其他的key相关联的value也跟着变。
6、items()
一般用于循环
names = {"name1":"alex","name2":"rain","name3":"jack"}
效率低
for k,v in names.items():
print(k,v)
>>name1 alex
name2 rain
name3 jack
相当于:for key in names:
print(key,names[key])
效率高
keys.() 只循环所有key 默认也只循环key
values.() 只循环所有的值
7、popitem() 随机删除一个键-值对
8、setdefaul 获取键-值,如果没有则添加
print(names.setdefaul("name4","plc"))
如果存在name4 则显示name4对应的key,如果没有则把name4:plc 添加到names字典中
9、update() 合并两个字典,当新字典中出现原来字典的键但值不一样时,合并时按新的来。
10、.copy()
info = {"No1":"alex","No2":"rain","No3":{"name":"alex","age":22}}
info2 = info.copy()
print(info)
print(info2)
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
可以看到两份数据是一样的,因为它们指向的都是同一个内存空间。
当修改原来的数据时看coyp是否有变化
info2["No2"] = "RAIN"
print(info)
print(info2)
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
{'No1': 'alex', 'No2': 'RAIN', 'No3': {'name': 'alex', 'age': 22}}
可以看到不一样了,再次修改内置字典的值看是否还有变化
info2["No3"]["age"] = 30
print(info)
print(info2)
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 30}}
{'No1': 'alex', 'No2': 'RAIN', 'No3': {'name': 'alex', 'age': 30}}
可以看到两份数据都变了。What happend ?
其实和前面说过的fromkeys(),原来是一样的,当你修改一个key(修改第一层)时它会重新开辟一块内存空间,原来的指向就会发生改变,
当你修改字典中一个内置字典或列表时,它不会开辟新的内存空间,原来的指向都不会变,所以两份数据是一样的.
11、如果想要独立的copy数据(copy出来的数据和原理的数据指向不一样)
引入函数 import copy
import copy
info = {"No1":"alex","No2":"rain","No3":{"name":"alex","age":22}}
info3 = copy.deepcopy(info)
print(info)
print(info3)
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
可以看到两份数据也同样是一样的
这次再按照前面的修改时,看下变化
info3["No2"] = "RAIN"
print(info)
print(info3)
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
{'No1': 'alex', 'No2': 'RAIN', 'No3': {'name': 'alex', 'age': 22}}
再修第二层的值时
info3["No3"]["age"] = 33
print(info)
print(info3
>>{'No1': 'alex', 'No2': 'rain', 'No3': {'name': 'alex', 'age': 22}}
{'No1': 'alex', 'No2': 'RAIN', 'No3': {'name': 'alex', 'age': 33}}
12、小知识点:
字典的查询速度比列表快,因为字典的key是唯一的,字典通过hash实现的key唯一
hash是把字符串通过一定的数学算法生成唯一的数值序列,生成的数值是在当前的
的程序中唯一。
hash会把key转化成数值后自动排序,再通过二分法查找,而列表再查找时,
得自己内部先排序,再通过二分等算法查找。
三、文件操作基础
1、文件操作流程:
打开一个文件,得到文件句柄并赋值给一个变量
通过句柄对文件操作
关闭文件
2、基本操作:
打开文件: file只能在2.x系列中
open() 例如打开文件lyric并查看
print(open("lyric"))
>> <_io.TextIOWrapper name='lyric' mode='r' encoding='cp936'>
相当于打开了文件对象,并没有把数据加载到内存,是在硬盘上找到了文件了并且获取了它的位置,把文件对象打印到了内存
要把数据加载到内存可以通过:print(open("lyric",encoding="utf8").read())
这样就可以显示lyric文件内容了,要对文件进行操作,先对加载到内存的文件赋个变量
data = open("lyric",encoding="utf8").read() 然后在进行修改,例如替换某个字符串
print(data.replace("Somehow","HHHAAA")) 把字符串Somehow 替换成 HHHAAA,可以实现
下一步要保存修改后的文件到硬盘,该如何操作呢?
现在无法保存了,因为你打开文件对象后直接read了并赋值给data了,所以open("lyric",encoding="utf8")的文件位置并没有
保存下来,就丢了找不到了。
所以要打开文件后并赋值保存它的位置:f = open("lyric",encoding="uft8")
然后再去读:data = f.read()
再去修改:data = data.replace("Somehow","HHHAAA")
最后再去写入硬盘:f.write(data) 能否成功呢?显然是不能会报文件不能写的错误
因为python在操作文件时,要么是打开只读的,要么是打开只写的。python的默认模式就是以读打开的
3、打开文件的模式有:
r,只读模式(默认)。
w,只写模式。【不可读;不存在则创建;存在则删除内容;】
a,追加模式。【可读; 不存在则创建;存在则只追加内容;】
"+" 表示可以同时读写某个文件
r+,可读写文件。【可读;可写;可追加】
w+,写读
a+,同a
"U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
rU
r+U
"b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
rb
wb
ab
所以对文件正确的打开方式是:
f = open("lyric",mode="r",encoding="utf-8") 以读的模式打开
f = open("lyric",mode="w",encoding="utf-8") 以写的模式打开
以读模式打开的文件不能写,以写模式打开的文件不能读,当以写模式打开文件后
相当于创建文件,原有的文件会被覆盖,直接关闭会保存:f.close()
那该怎么修改文件后保存呢:
1、以r模式打开
f = open("lyric",mode="r",encoding="utf-8")
data = f.read()
data = data.replace("Somehow","HHHAAA")
f.close()
f = open("lyric",mode="w",encoding="utf-8")
f.wite(data)
f.close()
这样就可以修改后并保存了,但是这种方法太吃内存需要把文件全读到内存。
2、一行一行的读,读完一行后再写到新文件中,然后把旧文件删掉,把新文件名改成旧文件的名
但是当读完时刻,新文件也写完了,这时会有两文件占两倍的硬盘空间。
一行行读的语法.readline()
for line in f:
print(line)相当于print(f.readline())
读取前五行:
for i in range(5):
print(f.readline().strip())
或者:
line_nu = 0
for line in f:
if line_nu < 5:
print(line.strip())
line_nu += 1
else:
break
要删除旧文件并且把新文件重命名想,需要引入 os 函数
完整的代码:
import os
f = open("lyric",mode="r",encoding="utf-8")
f_new = open("lyric_new",mode="w",encoding="utf-8")
for line in f:
if "HHHAAA"in line:
line = line.replace("HHHAAA","Somehow")
f_new.write(line)
f.close() f_new.close()
os.remove("lyric")
os.renames("lyric_new","lyric")