一:集合
python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算.
sets 支持 x in set, len(set),和 for x in set。作为一个无序的集合,sets不记录元素位置或者插入点。因此,sets不支持 indexing, slicing, 或其它类序列(sequence-like)的操作。 下面来点简单的小例子说明把。 >>> x = set('spam') >>> y = set(['h','a','m']) >>> x, y (set(['a', 'p', 's', 'm']), set(['a', 'h', 'm'])) 再来些小应用。 >>> x & y # 交集 set(['a', 'm']) >>> x | y # 并集 set(['a', 'p', 's', 'h', 'm']) >>> x - y # 差集 set(['p', 's']) 记得以前个网友提问怎么去除海量列表里重复元素,用hash来解决也行,只不过感觉在性能上不是很高,用set解决还是很不错的,示例如下: >>> a = [11,22,33,44,11,22] >>> b = set(a) >>> b set([33, 11, 44, 22]) >>> c = [i for i in b] >>> c [33, 11, 44, 22] 很酷把,几行就可以搞定。 1.8 集合 集合用于包含一组无序的对象。要创建集合,可使用set()函数并像下面这样提供一系列的项: s = set([3,5,9,10]) #创建一个数值集合 t = set("Hello") #创建一个唯一字符的集合 与列表和元组不同,集合是无序的,也无法通过数字进行索引。此外,集合中的元素不能重复。例如,如果检查前面代码中t集合的值,结果会是: >>> t set(['H', 'e', 'l', 'o']) 注意只出现了一个'l'。 集合支持一系列标准操作,包括并集、交集、差集和对称差集,例如: a = t | s # t 和 s的并集 b = t & s # t 和 s的交集 c = t – s # 求差集(项在t中,但不在s中) d = t ^ s # 对称差集(项在t或s中,但不会同时出现在二者中) 基本操作: t.add('x') # 添加一项 s.update([10,37,42]) # 在s中添加多项 使用remove()可以删除一项: t.remove('H') len(s) set 的长度 x in s 测试 x 是否是 s 的成员 x not in s 测试 x 是否不是 s 的成员 s.issubset(t) s <= t 测试是否 s 中的每一个元素都在 t 中 s.issuperset(t) s >= t 测试是否 t 中的每一个元素都在 s 中 s.union(t) s | t 返回一个新的 set 包含 s 和 t 中的每一个元素 s.intersection(t) s & t 返回一个新的 set 包含 s 和 t 中的公共元素 s.difference(t) s - t 返回一个新的 set 包含 s 中有但是 t 中没有的元素 s.symmetric_difference(t) s ^ t 返回一个新的 set 包含 s 和 t 中不重复的元素 s.copy() 返回 set “s”的一个浅复制 请注意:union(), intersection(), difference() 和 symmetric_difference() 的非运算符(non-operator,就是形如 s.union()这样的)版本将会接受任何 iterable 作为参数。相反,它们的运算符版本(operator based counterparts)要求参数必须是 sets。这样可以避免潜在的错误,如:为了更可读而使用 set('abc') & 'cbs' 来替代 set('abc').intersection('cbs')。从 2.3.1 版本中做的更改:以前所有参数都必须是 sets。 另外,Set 和 ImmutableSet 两者都支持 set 与 set 之间的比较。两个 sets 在也只有在这种情况下是相等的:每一个 set 中的元素都是另一个中的元素(二者互为subset)。一个 set 比另一个 set 小,只有在第一个 set 是第二个 set 的 subset 时(是一个 subset,但是并不相等)。一个 set 比另一个 set 打,只有在第一个 set 是第二个 set 的 superset 时(是一个 superset,但是并不相等)。 子 set 和相等比较并不产生完整的排序功能。例如:任意两个 sets 都不相等也不互为子 set,因此以下的运算都会返回 False:a<b, a==b, 或者a>b。因此,sets 不提供 __cmp__ 方法。 因为 sets 只定义了部分排序功能(subset 关系),list.sort() 方法的输出对于 sets 的列表没有定义。 运算符 运算结果 hash(s) 返回 s 的 hash 值 下面这个表列出了对于 Set 可用二对于 ImmutableSet 不可用的运算: 运算符(voperator) 等价于 运算结果 s.update(t) s |= t 返回增加了 set “t”中元素后的 set “s” s.intersection_update(t) s &= t 返回只保留含有 set “t”中元素的 set “s” s.difference_update(t) s -= t 返回删除了 set “t”中含有的元素后的 set “s” s.symmetric_difference_update(t) s ^= t 返回含有 set “t”或者 set “s”中有而不是两者都有的元素的 set “s” s.add(x) 向 set “s”中增加元素 x s.remove(x) 从 set “s”中删除元素 x, 如果不存在则引发 KeyError s.discard(x) 如果在 set “s”中存在元素 x, 则删除 s.pop() 删除并且返回 set “s”中的一个不确定的元素, 如果为空则引发 KeyError s.clear() 删除 set “s”中的所有元素 请注意:非运算符版本的 update(), intersection_update(), difference_update()和symmetric_difference_update()将会接受任意 iterable 作为参数。从 2.3.1 版本做的更改:以前所有参数都必须是 sets。 还请注意:这个模块还包含一个 union_update() 方法,它是 update() 方法的一个别名。包含这个方法是为了向后兼容。程序员们应该多使用 update() 方法,因为这个方法也被内置的 set() 和 frozenset() 类型支持。
二:文件操作
对文件进行操作的流程:
第一,打开文件,得到文件句柄并复制给一个变量。 第二,打开句柄对文件进行操作。 第三,关闭文件。(1)r模式
在只读模式下写入内容会报错。
1 f = open('file1','r')2 f_read = f.read() #read是逐字符地读取,read可以指定参数,设定需要读取多少字符,无论一个英文字母还是一个汉字都是一个字符。3 print(f_read)4 f.close()
1 f = open('file1','r')2 f_read = f.readline() #readline只能读取第一行代码,原理是读取到第一个换行符就停止。3 print(f_read)4 f.close()
1 f = open('file1','r')2 f_read = f.readlines() #readlines会把内容以列表的形式输出。3 print(f_read)4 f.close()
1 f = open('file1','r')2 for line in f.readlines() #使用for循环可以把内容按字符串输出。3 print(line) #输出一行内容输出一个空行,一行内容一行空格... 因为文件中每行内容后面都有一个换行符,而且print()语句本身就可以换行,如果不想输出空行,就需要使用下面的语句:print(line.strip())4 f.close()
(2)w模式
在进行操作前,文件中所有内容会被清空。比如在file1中写入'hello world',程序执行后file1中就只剩下一句'hello world'
1 f = open('file1','w',encoding='utf8') #由于Python3的默认编码方式是Unicode,所以在写入文件的时候需要调用utf8,以utf8的方式保存,这时pycharm(默认编码方式是utf8)才能正确读取,当读取文件时,文件是utf8格式,pycharm也是utf8,就不需要调用了。2 f_w = f.write('hello world')3 print(f_w) #有意思的是,这里并不打印'hello world',只打印写入多少字符4 f.close()
(3)a模式
与w模式不同的是,a模式不会把原来内容清空,而是光标移到内容最后位置,继续写入新内容。比如在最后追加'hello world'
f = open('file1','a')f_a = f.write('hello world')print(f_a) #还是会打印写入的字符数f.close()
1 f = open('file','r') 2 data=f.readlines() #注意及时关闭文件 3 f.close() 4 5 num = 0 6 for i in data: 7 num += 1 8 if num == 5: 9 i = ''.join([i.strip(),'hello world']) #不要使用“+”进行拼接10 print(i.strip())11 f.close()
对于大数据文件,要使用下面的方法:
1 num = 02 f.close() #不要过早关闭文件,否则程序不能识别操作句柄f.3 f = open('file','r')4 for i in f: #for内部把f变为一个迭代器,用一行取一行。5 num += 16 if num == 5:7 i = ''.join([i.strip(),'hello world'])8 print(i.strip())9 f.close()
3.tell和seek
tell:查询文件中光标位置
seek:光标定位
1 f = open('file','r') 2 print(f.tell()) #光标默认在起始位置 3 f.seek(10) #把光标定位到第10个字符之后 4 print(f.tell()) #输出10 5 f.close() 6 ---------------------- 7 f = open('file','w') 8 print(f.tell()) #先清空内容,光标回到0位置 9 f.seek(10) 10 print(f.tell())11 f.close()12 ----------------------13 f = open('file','a')14 print(f.tell()) #光标默认在最后位置15 f.write('你好 世界')16 print(f.tell()) #光标向后9个字符,仍在最后位置17 f.close()
4.flush 同步将数据从缓存转移到磁盘
示例,实现进度条功能
1 import sys,time #导入sys和time模块 2 for i in range(40): 3 sys.stdout.write('*') 4 sys.stdout.flush() #flush的作用相当于照相,拍一张冲洗一张 5 time.sleep(0.2) 6 下面代码也能够实现相同的功能 7 import time 8 for i in range(40): 9 print('*',end='',flush=True) #print中的flush参数10 time.sleep(0.2)
5.truncate 截断
不能是r模式下执行,
w模式下,已经清空所有数据,使用truncate
没有任何意义,
a模式下,截断指定位置后的内容。
1 f = open('file','a')2 f.truncate(6) #只显示6个字节的内容(6个英文字符或三个汉字),后面的内容被清空。
6.光标位置总结
一个汉字两个字节,涉及光标位置的方法有4个:read
、tell
、seek
、truncate
。
1 #--------------------------光标总结head----------------------------------- 2 f = open('file','r') 3 print(f.read(6)) #6个字符 4 print(f.tell()) #位置12字节,一个汉字两个字节,按字符计数 5 f.close() 6 7 f = open('file','r') 8 f.seek(6) #6个字节 9 print(f.tell())10 f.close()11 12 f = open('file','a')13 print(f.tell()) #光标默认在最后位置14 f.write('你好 世界')15 print(f.tell()) #光标向后9个字节,一个汉字两个字节,仍在最后位置 182-->19116 f.close()17 18 f = open('file','a',encoding='utf-8')19 print(f.truncate(6)) #由于需要光标定位位置,所以也是字节。只显示6个字节的内容(6个英文字母或三个汉字,一个汉字两个字节),后面的内容被清空。20 f.close()21 #-----------------------------光标总结end---------------------------------
7.另外3种模式:r+、w+、a+
r+:读写模式,光标默认在起始位置,当需要写入的时候,光标自动移到最后
w+:写读模式,先清空原内容,再写入,也能够读取
a+:追加读模式,光标默认在最后位置,直接写入,也能够读取。
1 f = open('file','a') 2 print(f.tell()) #末尾207位置 3 f.close() 4 5 f = open('file','r+') 6 print(f.tell()) #0位置 7 print(f.readline()) #读取第一行 8 f.write('羊小羚') #光标移到末尾207位置并写入 9 print(f.tell()) #213位置10 f.seek(0) #光标移到0位置11 print(f.readline()) #读取第一行12 f.close()
8.修改文件内容
思路:由于数据存储机制的关系,我们只能把文件1中的内容读取出来,经过修改后,放到文件2中。
1 f2 = open('file2','w',encoding='utf8') #写入的时候必须加utf8 2 f1 = open('file','r') 3 num = 0 4 for line in f1: #迭代器 5 num += 1 6 if num == 5: 7 line = ''.join([line.strip(),'羊小羚\n']) #里面就是对字符串进行操作了 8 f2.write(line) 9 f1.close()10 f2.close()
9.with语句
可以同时对多个文件同时操作,当with
代码块执行完毕时,会自动关闭文件释放内存资源,不用特意加f.close()
,我们通过下面的示例体会with
的用法和好处。
用with
语句重写8中的代码
1 num = 02 with open('file','r') as f1,open('file2','w',encoding='utf8') as f2:3 for line in f1:4 num += 15 if num == 5:6 line = ''.join([line.strip(),'羊小羚'])7 f2.write(line)
三、函数
函数能提高应用的模块性,和代码的重复利用率。Python提供了许多内建函数,比如print()等。也可以创建用户自定义函数。
函数定义
函数定义的简单规则:
函数代码块以def关键词开头,后接函数标识符名称和圆括号(),任何传入参数和自变量必须放在圆括号中间
函数内容以冒号起始,并且缩进若有返回值,Return[expression] 结束函数;不带return 表达式相当于返回None函数通常使用三个单引号 '''...''' 来注释说明函数;函数体内容不可为空,可用 pass 来表示空语句;以下几个为简单的函数示例:
1 ''' some basic functions ''' 2 def func1(): # 函数无传入参数 3 print("func1") # 无return值 4 func1() # 函数调用 5 6 def func2(): 7 return("func2") # return 字符串 "func2" 8 print(func2()) 9 10 def func3(a,b): # 需传两个参数11 print("a+b = %d" %(a+b)) # print表达式,无return12 func3(3,4)13 14 def func4(a,b): # 需传两个参数15 return (a+b) # return a+b 的值16 print(func4(4,3))
函数调用
定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。
上面的例子中 func1() 就是无参数函数的调用; func3(3,4) 为有参数函数的调用
深入函数定义
默认参数值
最常用的一种形式是为一个或过个参数指定默认值。调用时,可不传入有默认值的参数。参考下例:
1 ''' advanced: 简单询问框 ''' 2 def ask_ok(hint, retries=4, complaint='Yes or no, please!'): # 仅有hint是必须要传入的,retries 和 complaint 均有默认值 3 while True: 4 u = input(hint) 5 if u in ('y','ye','yes'): # in 的用法;若用户回答在('y','ye','yes') return True 6 return True 7 if u in ('n','no','nop','nope'): # 若用户回答在('n','no','nop','nope') return False 8 return False 9 retries = retries -1 # 若用户输入不在之前所列,可重试,重试次数-110 if retries <= 0 : # 若超出重试次数,raise自定义Error11 raise IOError('refusenik user')12 print(complaint) # 若用户输入不在之前所列,提示 complaint 信息13 14 result1 = ask_ok("Yes or No?") # 只给必要的参数值hint,可尝试输入'y' 'no' 等;输入其他的如 'x' 超过4次15 print(result1) # 查看return的值16 17 # result2 = ask_ok("Yes or No?",2) # 给出retries=2,尝试输入其他的如 'x' 超过2次 18 19 # result3 = ask_ok("Yes or No?",'Y or N?') # 不可只省略第二个参数,若尝试输入其他的如 'x',会报错20 21 # result4 = ask_ok("Yes or No?",3,'Y or N?') # 给出所有的参数,可尝试输入'y' 'no' 等;输入其他的如 'x' 超过3次22 # print(result4)
注意:默认值是在函数定义作用域被解析的,如下所示
1 '''默认值是在函数定义作用域被解析的'''2 i = 53 def print_i(var=i):4 print(var)5 i = 66 print_i() # 输出为5
重要警告:默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,如列表、字典或大多数类的实例。如下例,函数在后续调用过程中会累积之前传给它的参数。
1 ''' 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,如列表、字典或大多数类的实例。 2 函数在后续调用过程中会累积之前传给它的参数。 3 ''' 4 def append_L(a,L=[]): # 必须传参a,L不必须,为list,默认为空 5 L.append(a) 6 return L 7 print(append_L(1)) # 给出参数 a=1, 此时 L 已变为 [1] 8 print(append_L(2)) # 输出 [1,2] 9 print(append_L(3)) # 输出 [1,2,3]10 11 ''' L缺省时,做改变L,而不是累积值,可像下方这样定义函数 '''12 def change_L(a,L=None):13 if L is None:14 L = []15 L.append(a)16 return L17 print(change_L(1)) # 给出参数 a=1, L为None18 print(change_L(2)) # 给出参数 a=2, L为None 输出 [2]19 print(change_L(3,[0])) # 给出参数 a=1, L=[0] 输出 [0,3]
关键字参数
上面的例子中,调用函数给出的参数都是根据定义的顺序来的。函数还可以根据 关键字函数 的形式来调用,参见下面的示例:
1 def add(a,b): 2 return (a+b) 3 print(add(b=9,a=2)) # 关键字参数定义 b=9 , a=2 与传参顺序无关4 # print(add(b=9,2)) # 会报错
可变参数列表
可以让函数调用可变个数的参数(不常用),这些参数被包装进一个元组。在这些可变个数的参数之前,可以有零到多个普通的参数。
可变参数的表示为在其参数名前加*,如*args;参见下面的示例:
1 def join_bysep(*strs,sep): # strs 可为多个参数2 return sep.join(strs) # 字符串连接函数 sep.join(str)3 print(join_bysep("red","blue","green",sep=" "))4 print(join_bysep("red","blue",sep=","))5 print(join_bysep("red",sep=","))6 print(join_bysep(sep=",")) # 无strs传参,为一空的字符串
#_*_ coding:utf-8 _*_ def func(x,y=2): print('我是形参%s'%x) print('我是默认参y--->%s'%y) func(1) #1是实参,x为形参,y为默认参数 #若实参数目不固定 def func1(*args): print(args) func1([1,2.3,4,5]) #([1, 2.3, 4, 5],) func1(*[1,2,3,4,5]) #(1, 2, 3, 4, 5) #实参为字典 **kwargs把N个关键字参数转化为字典输出 def func2(**kwargs): print(kwargs) print(kwargs['name']) print(kwargs['age']) print(kwargs['salary']) func2(name='Andy',age=20,salary=10000,job='doctor') def func3(name,age=20,**kwargs): print(name) print(age) print(kwargs) func3('Andy') #Andy #{} #默认参数赋值方式:1、位置参数赋值 2、关键字赋值 func3('Andy',salary=10000,age=21) func3('Andy',21,salary=10000) #*args接受N个位置参数,转化成元组; #**kwargs接收N个关键字参数,转为字典 #位置参数必须放在关键字参数前面 # def func4(name,age=20,*args,**kwargs): # print(name) # print(age) # print(args) # print(kwargs) # logger('test') # func4('Andy',21,32,salary=10000,job='doctor') # def logger(source): # print('from %s'%source) #局部变量(只在函数体内作用的变量) def changename(name): print('before change',name) name='John' age=23 print('after change',name) name='Andy' changename(name) print(name) # before change Andy # after change John # Andy #全局变量(整个程序都可以用的变量,定义在函数体外)若修改全局变量,需在函数体内用global 重新定义变量 ***函数体内不要修改 # 全局变量,且函数体内不要定义全局变量 def func5(): global name name='andy' print(name) func5() print(name) #全局变量(整个程序都可以用的变量,定义在函数体外)若修改全局变量,需在函数体内用global 重新定义变量 ***函数体内不要修改 # 全局变量,且函数体内不要定义全局变量 #列表、字典、集合、类作为全局变量时,函数体内可以修改 #字符串、数字作为全局变量时,函数体内无法修改 #函数的递归 def calc(n): print(n) if int(n/2) >0: return calc(int(n/2)) print(n) calc(10)