第三周笔记

一:集合

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()


在r模式时,我们说过用for循环和readlines()输出文件内容,这种输出内容的原理是:打开文件,把全部内容读入内存,然后再打印输入,当文件很大时,这种读取方式就不靠谱了,甚至会使机器崩溃。我们需要及时关闭文件,如下:

 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 = 0
2 f.close()  #不要过早关闭文件,否则程序不能识别操作句柄f.
3 f = open('file','r')
4 for i in f:  #for内部把f变为一个迭代器,用一行取一行。
5   num += 1
6   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个:readtellseektruncate

 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-->191
16 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 = 0
2 with open('file','r') as f1,open('file2','w',encoding='utf8') as f2:
3   for line in f1:
4     num += 1
5     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表达式,无return
12 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                  # 若用户输入不在之前所列,可重试,重试次数-1
10         if retries <= 0 :                     # 若超出重试次数,raise自定义Error
11             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 = 5
3 def print_i(var=i):
4     print(var)
5 i = 6
6 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 L
17 print(change_L(1))            # 给出参数 a=1, L为None
18 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传参,为一空的字符串

python3 函数的形参、实参、位置参数、默认参数、关键字参数以及函数的递归

#_*_ 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)
posted @ 2017-11-19 20:35  wwtww521  阅读(204)  评论(0编辑  收藏  举报