Long Way To Go 之 Python 3
集合set
集合是无序的
作用:1.去重 eg. 把list转成set可自动去重
2.关系测试 eg. 交集、并集、差集等
举个栗子:Python班有个名字列表1,Linux班有个名字列表2,但是现在有人报了两个班,想计算出报名的总人数
——> 可用集合删除重复数据
如果不用集合,用现已知的知识
——> 创建一个空list
for循环(已有的包含重复名的list)
每一次循环元素,就扔到空列表里,但是要先判断元素是否已经在空list里存在
操作操作~~~
基本:
# define set list_1 = [1,4,5,7,3,6,7,9] list_1 =set(list_1) # 大括号,有点像字典,但是不是字典 list_2 = set([2,6,0,66,22,8,4]) print(list_1,list_2) # intersection交集 print(list_1.intersection(list_2)) # union并集 print(list_1.union(list_2)) # difference差集 print(list_1.difference(list_2)) # in list 1 but not in list 2 print(list_2.difference(list_1)) # in list 2 but not in list 1 # subset子集 print(list_1.issubset(list_2)) # superset 超集 print(list_1.issuperset(list_2)) list_3 = set([1,3,7]) print(list_3.issubset(list_1)) print(list_1.issuperset(list_3)) # 对称差集 print(list_1.symmetric_difference(list_2)) # 互相都没的取出来了 # 判断交集 list_4 = set([5,6,8,7]) print(list_3.isdisjoint(list_4)) # return True if two sets have a null intersection
运算符:
# 交集 print(list_1 & list_2) # 并集 print(list_2 | list_1) # 差集 print(list_1 - list_2) # 在1中不在2 # 对称差价 print(list_1 ^ list_2) # 互相重复的去掉,取剩下的
增删:
# 增 add 集合没有insert,只有add list_1.add(99) # add one element list_1.update([888,777]) # add more elements # 删 remove list_1.remove(99) # 另外两个删除方法:pop & discard list_1.pop() #remove and return an arbitrary set element list_1.discard(999) ## remove an element from a set if it is a member, if the element is not in the set, do nothing # 判断 element x 在不在set s 里面 x in s x not in s # set s 的长度 len(s)
浅copy:
list_1.copy()
文件:
文件操作流程:
- 打开文件,得到文件句柄并赋值给一个变量
- 通过句柄对文件进行操作
- 关闭文件(用with可自动关闭文件)
操作操作~~
基本1:
# normal way f = open("yesterday","a",encoding="utf=8") data = f.read() # 只读 print("---read----",data) f.close() # 关闭文件 # using "with": close file automatically with open("yesterday","r",encoding = "utf-8") as f: # 相当于 f = open("yesterday","r",encoding = "utf-8") for line in f: print(line) # open multiple files with open("o1") as obj1,\ open("o2") as obj2:
ps: windows 打开文件,默认是GBK,但是Python默认处理编码是UTF-8,但是UTF-8 不能处理GBK,所以要用UTF-8来打开文件
另外,打开文件的模式:
r : 只读(如果不写模式,默认是r)
w : 只写(只可写,如果文件不存在则创建,如果存在就会覆盖原内容)
a : 追加(可读可写,如果文件不存在则创建,如果存在就追加) ps: 只能追加到最后
升级版模式:
r+ : 读写(可读可写可追加)
w+ :写读(并没什么卵用)
a+ : 同a
”U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
rU
r+U
处理二进制文件时:(eg.视频文件)
rb
wb
ab
二进制文件不是说文件内容变成0110001这种形式,而是文件是以二进制编码储存的
基本2:
#只读前五行 for i in range(5): print(f.readline()) # 假如文件内存很大,f.readlines只适合读小文件 # 可以读一行,但是不存在内存里,内存里只保存一行;就是循坏一行,删掉一行 count = 0 # 文件不是列表了,变成了迭代器 for line in f: if count == 9: print("---------我是分割线----------") count += 1 continue print(line) count += 1 # tell & seek print(f.tell()) # tell是按照已读的字符来计数的 f.seek(0) # 光标回到第二行,回不去,只能回到0 print(f.tell()) # return 0 f.seek(10) # 从第十个字母开始 print(f.flush()) # 刷新 # 以写的模式,打开文件,写完一行就默认写到硬盘上了,但是其实不一定; # 刚写完一行,然后突然断电,这一行就可能没写进去 # 所以现在,每写一行,会暂时存在内存的缓存里,等缓存大小满了,就一次性刷到硬盘上,有可能会好几行一起写到硬盘 # truncate f = open("yesterday","a",encoding="utf=8") #f.truncate() # 文件清空 在w模式下 f.seek(10) #在这里,移动不好使 f.truncate(20) # 从文件开头第20个字母开始截断
文件修改:
with open("yesterday","r",encoding = "utf-8") as f,\ open("yesterday.bak","w",encoding = "utf-8") as f_new: for line in f: if "肆意的快乐" in line: line = line.replace("肆意的快乐等我享受","肆意的快乐等alex享受") f_new.write(line) # 输入参数,再替换 import sys with open("yesterday","r",encoding = "utf-8") as f,\ open("yesterday.bak","w",encoding = "utf-8") as f_new: find_str = sys.argv[1] replace_str = sys.argv[2] for line in f: if find_str in line: line = line.replace(find_str,replace_str) f_new.write(line)
字符编码
需知:
1.在python2默认编码是ASCII, python3里默认是unicode
2.unicode 分为 utf-32(占4个字节),utf-16(占两个字节),utf-8(占1-4个字节), so utf-16就是现在最常用的unicode版本, 不过在文件里存的还是utf-8,因为utf8省空间
3.在py3中encode,在转码的同时还会把string 变成bytes类型,decode在解码的同时还会把bytes变回string
转码流程:(其他转码也是通过和unicode的encode/decode来操作)
pyhton2:
如果文件头声明了#_*_coding:utf-8 _*_,就可以写中文了,然后以下代码都是utf-8的格式; 如果不声明,python在处理这段代码时按ASCII,然后会报错。
#_*_coding:utf-8 _*_ s = “你好” #你好这个字符是utf-8格式 s = u"你好” # 你好这个字符就是unicode格式 # utf-8 转成 gbk s_to_gbk = s.decode("utf-8").encode("gbk")
python3:
默认的文件编码是utf-8,可以直接写中文,也不需要文件头声明编码了。
# utf 转 gbk s = “你好” #变量默认是unicode编码,不是utf-8,所以转换时不用解码 print(s.encode("gbk")) # 直接encode成gbk # 但是print出来是没有显示中文的,因为文件编码是utf-8
改一下~~
# _*_ coding: gbk _*_ # 改的只是文件编码,但是python3里还是默认的unicode s = "你好" # 是个unicode,所以没有s.decode()操作 print(s.encode("gbk")) #现在print出来是gbk了,但是显示也不是中文,是因为显示的是bytes类型
函数
指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
why 函数?
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
1.定义:
# define a function 函数 def func1(): # 函数名,空号内可定义参数 """testing1""" # 文档描述,强烈建议写上 print("in the func1") # 函数体 return 0 # define a progress 过程 def func2(): """testing2""" print("in the func2") #调用函数 x = func1() # x 是接收func1的返回值 y = func2() # 返回none
带参数定义:
def calc(x,y): res = x**y return res #返回函数执行结果 c = calc(a,b) #结果赋值给c变量 print(c)
嵌套式函数:
name = "Alex" def change_name(): name = "Alex2" def change_name2(): name = "Alex3" print("第3层打印",name) change_name2() #调用内层函数 print("第2层打印",name) change_name() print("最外层打印",name)
2.参数:
a) 形参和实参:
b)默认参数
默认参数特点: 调用函数的时候,默认参数可有可无(非必须传递)
用途:(比如一键安装)默认安装值
IMPORTANR ! 关键参数必须放在位置参数之后 (关键参数就是默认参数,位置参数如上图xyab)
def test(x,y=2): # 默认参数 print(x) print(y) test(1) # print出来是1 2 test(1,y=3) # print出来是1 3
c) 关键参数(参照b))
d) 非固定参数
函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数
eg.1
def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式 print(name,age,args) stu_register("Alex",22) #输出 #Alex 22 () #后面这个()就是args,只是因为没传值,所以为空 stu_register("Jack",32,"CN","Python") #输出 # Jack 32 ('CN', 'Python')
eg.2
# 不传递元组,传递字典 # **kwargs : 把n个关键字参数,转化成字典的方式 def test2(**kwargs): print(kwargs) test2(name="alex",age=8,sex="F") # 输出 #{'name': 'alex', 'age': 8, 'sex': 'F'}
eg.3
def test3(name,age=18,*args,**kwargs): # 一个位置参数,一个默认参数 #默认参数一定要放在参数组前面,参数组一定要往后放 print(name) print(age) print(args) print(kwargs) test3("alex",age = 34, sex ="m",hobby = "tesla") # 全给字典了 # *args 不能接受关键字,只接受位置参数,所以是空的元组 # 输出 alex 34 () {'sex': 'm', 'hobby': 'tesla'}
3.局部变量
def change_name(name): print("before change",name) name = "Alex Li" # 局部变量,只在函数里有效,这个函数就是这个变量的作用域 print("after change",name) name = "alex" change_name(name) print(name) # 还是alex, Alex 只是局部变量 #输出 #before change alex #after change Alex Li #alex
4.全局变量
school = "Oldboy edu." # 全局变量 def change_name(name): school = "Mage Linux" print("before change",name,school) name = "Alex Li" print("after change",name) print(school) name = "alex" change_name(name) print(name) # 还是alex, Alex 只是局部变量 print(school) #输出 #Oldboy edu. #before change alex Mage Linux #after change Alex Li #alex #Oldboy edu.
5.返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
- 如果return多个值,就全部会包含在元组中
- retrun的值可以是个数,也可以是字符串、列表、字典等
6.递归
在函数内部,可以调用其他函数。如果调用的是本身,这个函数就是递归函数。
特点:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,如果递归调用的次数过多,会导致栈溢出
def calc(n): print(n) if int(n/2) > 0: return calc(int(n/2)) print("---->",n) calc(10) #输入 #10 #5 #2 #1 #----> 1
7.匿名函数
#这段代码 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n:n**n print(calc(10)) #匿名函数主要是和其它函数搭配使用的 res = map(lambda x:x**2,[1,5,7,4,8]) for i in res: print(i) #输出 #1 #25 #49 #16 #64
8.函数式编程
"函数式编程"是一种“编程范式”(programming paradigm),也就是如何编写程序的方法论。主要思想是把运算过程尽量写成一系列嵌套的函数调用。
9.高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
# 普通函数 def add(a,b): # 算一个加法 return a+b # 高阶函数 def add(a,b,f): return f(a)+f(b) res = add(3,-6,abs) # abs 本身就是个函数 absolute print(res)
附加~~~~~·
简易进度条:
import sys,time # 一个一个蹦出来 for i in range(20): sys.stdout.write("#") sys.stdout.flush() time.sleep(0.1)