第三章:Python基础の函数和文件操作实战
本課主題
- Set 集合和操作实战
- 函数介紹和操作实战
- 参数的深入介绍和操作实战
- format 函数操作实战
- lambda 表达式介绍
- 文件操作函数介紹和操作实战
- 本周作业
Set 集合和操作实战
Set 是一个无序且不容许重复的序列
创建集合有两种方式:
- 第一种是通过直接创建、例如:s = {11,22}
1 >>> se = {11,222,11,222} 2 >>> print(se) 3 {11, 222} 4 >>> type(se) 5 <class 'set'>
- 第二种是通过转换。从一个可迭代类型的数组、元组转换成集合 Set。例如:s = Set(list)
1 >>> li = [11,22,11,33,11,44,55] 2 >>> se = set(li) #把列表转换成集合 3 >>> se 4 {33, 11, 44, 22, 55} 5 >>> type(se) 6 <class 'set'>
原理:在调用 Set 函数时,它会自动调用 __intit__ 方法,这叫构造方法 ,其实内部会执行一个 For 循环,循环这个"可迭代对象"里的所有元素,一个一个添加到集合里(什么是构造方法会在后期学到面向对象后再分享)
Set 集合的功能
这是Set 集合在 Python3.5.2的源码,我把它贴进来,里面有很多双下划线的方法,现在我都不知道是什么,让我了解后会回来补充一下。现在最主要的是要了解下面这几个集合的功能:我把它归类为添加、更新、找不同、找相同、删除和返回Boolean值六大类。
class set(object): """ set() -> new empty set object set(iterable) -> new set object Build an unordered collection of unique elements. """ def add(self, *args, **kwargs): # real signature unknown """ Add an element to a set. This has no effect if the element is already present. """ pass def clear(self, *args, **kwargs): # real signature unknown """ Remove all elements from this set. """ pass def copy(self, *args, **kwargs): # real signature unknown """ Return a shallow copy of a set. """ pass def difference(self, *args, **kwargs): # real signature unknown """ Return the difference of two or more sets as a new set. (i.e. all elements that are in this set but not the others.) """ pass def difference_update(self, *args, **kwargs): # real signature unknown """ Remove all elements of another set from this set. """ pass def discard(self, *args, **kwargs): # real signature unknown """ Remove an element from a set if it is a member. If the element is not a member, do nothing. """ pass def intersection(self, *args, **kwargs): # real signature unknown """ Return the intersection of two sets as a new set. (i.e. all elements that are in both sets.) """ pass def intersection_update(self, *args, **kwargs): # real signature unknown """ Update a set with the intersection of itself and another. """ pass def isdisjoint(self, *args, **kwargs): # real signature unknown """ Return True if two sets have a null intersection. """ pass def issubset(self, *args, **kwargs): # real signature unknown """ Report whether another set contains this set. """ pass def issuperset(self, *args, **kwargs): # real signature unknown """ Report whether this set contains another set. """ pass def pop(self, *args, **kwargs): # real signature unknown """ Remove and return an arbitrary set element. Raises KeyError if the set is empty. """ pass def remove(self, *args, **kwargs): # real signature unknown """ Remove an element from a set; it must be a member. If the element is not a member, raise a KeyError. """ pass __hash__ = None def symmetric_difference(self, *args, **kwargs): # real signature unknown """ Return the symmetric difference of two sets as a new set. (i.e. all elements that are in exactly one of the sets.) """ pass def symmetric_difference_update(self, *args, **kwargs): # real signature unknown """ Update a set with the symmetric difference of itself and another. """ pass def union(self, *args, **kwargs): # real signature unknown """ Return the union of sets as a new set. (i.e. all elements that are in either set.) """ pass def update(self, *args, **kwargs): # real signature unknown """ Update a set with the union of itself and others. """ pass def __and__(self, *args, **kwargs): # real signature unknown """ Return self&value. """ pass def __contains__(self, y): # real signature unknown; restored from __doc__ """ x.__contains__(y) <==> y in x. """ pass def __eq__(self, *args, **kwargs): # real signature unknown """ Return self==value. """ pass def __getattribute__(self, *args, **kwargs): # real signature unknown """ Return getattr(self, name). """ pass def __ge__(self, *args, **kwargs): # real signature unknown """ Return self>=value. """ pass def __gt__(self, *args, **kwargs): # real signature unknown """ Return self>value. """ pass def __iand__(self, *args, **kwargs): # real signature unknown """ Return self&=value. """ pass def __init__(self, seq=()): # known special case of set.__init__ """ set() -> new empty set object set(iterable) -> new set object Build an unordered collection of unique elements. # (copied from class doc) """ pass def __ior__(self, *args, **kwargs): # real signature unknown """ Return self|=value. """ pass def __isub__(self, *args, **kwargs): # real signature unknown """ Return self-=value. """ pass def __iter__(self, *args, **kwargs): # real signature unknown """ Implement iter(self). """ pass def __ixor__(self, *args, **kwargs): # real signature unknown """ Return self^=value. """ pass def __len__(self, *args, **kwargs): # real signature unknown """ Return len(self). """ pass def __le__(self, *args, **kwargs): # real signature unknown """ Return self<=value. """ pass def __lt__(self, *args, **kwargs): # real signature unknown """ Return self<value. """ pass @staticmethod # known case of __new__ def __new__(*args, **kwargs): # real signature unknown """ Create and return a new object. See help(type) for accurate signature. """ pass def __ne__(self, *args, **kwargs): # real signature unknown """ Return self!=value. """ pass def __or__(self, *args, **kwargs): # real signature unknown """ Return self|value. """ pass def __rand__(self, *args, **kwargs): # real signature unknown """ Return value&self. """ pass def __reduce__(self, *args, **kwargs): # real signature unknown """ Return state information for pickling. """ pass def __repr__(self, *args, **kwargs): # real signature unknown """ Return repr(self). """ pass def __ror__(self, *args, **kwargs): # real signature unknown """ Return value|self. """ pass def __rsub__(self, *args, **kwargs): # real signature unknown """ Return value-self. """ pass def __rxor__(self, *args, **kwargs): # real signature unknown """ Return value^self. """ pass def __sizeof__(self): # real signature unknown; restored from __doc__ """ S.__sizeof__() -> size of S in memory, in bytes """ pass def __sub__(self, *args, **kwargs): # real signature unknown """ Return self-value. """ pass def __xor__(self, *args, **kwargs): # real signature unknown """ Return self^value. """ pass __hash__ = None
添加: add( ), unions( )
更新: difference_update( ), symmeteric_difference_update( ), intersection_update( ), update( )
找不同: difference( ), symmeteric_difference( ),
找相同: intersection( )
删除: discard( ), remove( ), clear( ), pop( )
返回Boolean值: isdisjoint( ), issuperset( )
- 添加: add()
1 >>> se = set() #创建空集合 2 >>> se 3 set() 4 >>> se.add(123) #添加123到集合里 5 >>> se 6 {123}
- 清除所有在集合里的内容: clear()
1 >>> se = set() #创建一个空集合 2 >>> se.add(111) 3 >>> se.add(222) 4 >>> se.add(333) 5 >>> print(se) 6 {333, 222, 111} 7 >>> se.clear() #清除集合里的所有元素 8 >>> se 9 set()
- 对比两个集合,找其中一方的不同,相当于 database 里的 left outer join: difference()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s3 = s1.difference(s2) # 在s1中存在, s2中不存在 4 >>> s1 5 {33, 11, 22} 6 >>> s3 7 {11} 8 >>> s3 = s2.difference(s1) #在s2中存在, s1中不存在 9 >>> s3 10 {44}
- 对比两个集合,取出双方不同的元素: symmetric_difference()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s3 = s1.symmetric_difference(s2) #找出双方都不存在的元素 4 >>> s1 5 {33, 11, 22} 6 >>> s3 7 {11, 44}
1 >>> a = {11,22,33} 2 >>> b = {22,33,44} 3 >>> a.difference_update(b) #对比两个集合,找其中一方的不同,然后直接把结果更新到原来的集合 4 >>> a 5 {11}
- 更新: 对比两个集合,取出双方不同的元素,然后直接把结果更新到原来的集合:symmetric_difference_update()
1 >>> a = {11,22,33} 2 >>> b = {22,33,44} 3 >>> a.symmetric_difference_update(b) 4 >>> a 5 {11, 44}
- 刪除指定元素,不存在,不報錯!!:discard()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.discard(11) 4 >>> s1 5 {33, 22}
- 刪除指定元素,不存在,報錯!!!:remove()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.remove(11) 4 >>> s1 5 {33, 22} 6 >>> s1.remove(1111) 7 Traceback (most recent call last): 8 File "<stdin>", line 1, in <module> 9 KeyError: 1111
- 随机移取某个元素并获取这个元素: pop()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> ret = s1.pop() 4 >>> ret 5 33
- 对比两个集合,找双方交集部份,相当于 database 里的 inner join: intersection()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s3 = s1.intersection(s2) #找s1和s2相同的元素 4 >>> s3 5 {33, 22} 6 >>> s1 7 {33, 11, 22}
- 对比两个集合,找双方交集部份,相当于 database 里的 inner join,然后直接把结果更新到原来的集合:intersection_update()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.intersection_update(s2) #找相同然后直接更新 s1 4 >>> s1 5 {33, 22}
- 判断两个集合有没有交集部份,如果有便返回 False ;如果没有,则返回 True: isdisjoint()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.isdisjoint(s2) #有交集部分 4 False 5 6 >>> s1 = {11,55,66} 7 >>> s2 = {22,33,44} 8 >>> s1.isdisjoint(s2) #没有交集部分 9 True
- 判断两个集合有没有父子关系,有是 True, 沒有則 False: issuperset()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.issuperset(s2) #s1 不是 s2 的父序列 4 False 5 >>> 6 >>> s1 = {11,22,33} 7 >>> s2 = {22,33} 8 >>> s1.issuperset(s2) #s1 是 s2 的父序列 9 True
- 把两个集合连合然后去掉重覆的就是并集(这功能相当于 database, union 然后拿distinct value):union()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s3 = s1.union(s2) 4 >>> s3 5 {33, 22, 11, 44}
- 批量地把一托集合增加到目标集合,update()接收一个可以被迭代的对象 e.g. List、Tuple、String:update()
1 >>> s1 = {11,22,33} 2 >>> s2 = {22,33,44} 3 >>> s1.update({77,88,99}) 4 >>> s1 5 {33, 99, 22, 88, 11, 77} 6 >>> s1.update(s2) 7 >>> s1 8 {33, 99, 22, 88, 11, 44, 77} 9 >>>
difference( ) 和 difference_update( ) 的应用:
- s1 集合和 s2 集合的结果会保持不变,两个方法 difference() 和 symmetric_difference() 都会产生一个新的集合,所以在实际情景中如果需要重用 s1 和 s2 集合的时候,就不要用 differernce_updates() 和 symmetric_difference_update() 了。因为这两个函数会覆盖本來在 s1 里的结果。
- 如果以后不需要基於 s1 來操作,只需要拿最新结果的话,就可以用 differernce_updates() 和 symmetric_difference_update(),这里的好处是变量声明减少了就可以节省内存空间! ! !
案例实战
[更新中...]
函数介紹和操作实战
在还没有学函数之前,我们实现的代码是用很多条件判断(If-then-else)还有表达式的For 循环来实现功能,不免有很多重覆性的代码,其实这个过程叫"面向过程编程”,就是从上到下按照逻辑一点一点去写,如果遇到重覆的功能,最典型的操作就是复制和粘贴(Copy and Paste)
面向过程编程的缺点:
- 如果代码量多的话,不断的复制和粘贴,会导致代码缺乏了可阅读性;
- 不断使用重覆代码,代码量多,程序员也会很累,会导致代码缺乏了重用性。
**总结:基于以上两点的解决方安案是运用函数式编程!!函数是用来封装某些功能的,它的出现是为了增加代码的重用性,令代码更简洁,而且可以增加其可读性,以后如果要使用的话就直接调用这个函数就行啦! !
创建函数的步骤如下:
- 用 def 关键字来声明这是一个函数;
- 在 def 後面加一個空格,然后寫上一個名字代表函数名稱,以后就可以在内存里调用它;
- 名字加上后再加一个括号 ( );
- 然后在函数体里写上函数的内容:就是具体需要实现的功能;
- 然后加上返回值,如果沒有返回值的話 Python 会有一个默应的返回值 (None)
>>> def func(): ... print("123") ... >>> f1 = func() 123 >>> print("f1:",f1) f1: None
有返回值的意思是:函数可以被調用然後賦值到另外一個參數,也就是說一個函数可以像參數一樣被传递。
>>> def func(): ... return "123" ... >>> f1 = func() >>> print("f1:",f1) f1: 123
- 函数可以在括号里面输入参数。
案例实战
以下是一个发邮件的函数,把登录邮件和发邮件这个功能封装在一个叫 sendMail()的函数里,只要一调用这个功能,它就会运行同一样的代码来发送邮件,这就是函数。
def sendMail(): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText("Python Email testing",'plain','utf-8') msg['From'] = formataddr(["Janice", "janicecheng.python@gmail.com"]) msg['To'] = formataddr(["Janice", "janicecheng.python@gmail.com"]) msg['Subject']='主題' server = smtplib.SMTP("smtp.gmail.com", 587) server.starttls() server.login("janicecheng.python@gmail.com","password") server.sendmail("janicecheng.python@gmail.com",["janicecheng.python@gmail.com",], msg.as_string()) print("Mail Send Successfully") server.quit() sendMail()
- def sendMail( ): 这叫声明函数
- sendMail( ): 这叫执行函数
1 def sendMail(): 2 3 import smtplib 4 from email.mime.text import MIMEText 5 from email.utils import formataddr 6 7 msg = MIMEText("Python Email testing",'plain','utf-8') 8 msg['From'] = formataddr(["Janice", "janicecheng.python@gmail.com"]) 9 msg['To'] = formataddr(["Janice", "janicecheng.python@gmail.com"]) 10 msg['Subject']='主題' 11 12 server = smtplib.SMTP("smtp.gmail.com", 587) 13 server.starttls() 14 server.login("janicecheng.python@gmail.com","password") 15 server.sendmail("janicecheng.python@gmail.com",["janicecheng.python@gmail.com",], msg.as_string()) 16 17 print("Mail Send Successfully") 18 server.quit() 19 20 sendMail()
注意:
- 当你在声明变量和函数之后,函数体在声明的时倏不会被执行的,它们分别会放在内存里,等待被调用!
- 在函数中一旦执行了 return, 函数的执行过程立即终止
返回值的补充说明
下面有一个例子,如果两个函数有相同的名称,然后在同一个程序里执行,运行结果会是多少呢?
以下是程序运行時的顺序:
- 第一步:Python 运行程序的时候是从上而下执行的,在 f1 声明函数放在内存的时候,它把1+2 声明后,然后放在内存里
- 第二步:当程序运行时碰到第2个 f1函数时,它再次在内存中把1x 2 放在内存中,并且 f1 指向 (1 x 2)
- Python 有自己的垃圾回收机制,会定时把没有的变量或者函数删除掉。
- 第三步:声明一个变量把f1函数的返回值存储在里面
- 第四步:当调用 f1函数时,它实际上是运行 a1 * a2
- 第五步:然后实际运行 f1函数
- 第六步:打印出 ret 变量中的值
所以调用 f1函数时,它其实正在运行 a1 * a2的功能,这就是为什么答案会是 64的原因。
参数的深入介绍和操作实战
- 把参数传入然后在函数体里的内码块可以把这个参数当成变量的去使用,这种参数叫形式参数。当我们在调用程序的时候把参数传入然后执行,这种参数叫实际参数。在這個例子中,参数 target_email 叫形式参数;下面执行程序传入的 “Alex” 叫实际参数。
- 如果从内存的角度去看这两种参数的话,在调用sendmail( ) 然后传入“alex” 的时候,这个“alex” 的字符串就已经在内存中,这就相当于把“xxoo” 这个形式参数指向内存中的实际参数“alex”; 同样地;对于“eric” 这个实际参数,它在被调用的时候,”eric” 已经在内存中等待着,然后函数本身的形式参数就会指向“ eric ”,然后执行程序,这就是形式参数和实际参数的关系。
- 还有就是形式参数和实际参数的位置默认情况下是一一对应的
- 在Python中也可以定义默认参数,意思是在声明函数的时候,其中一些形式参数已经定义了一些默认值,注意:如果想要定义默认参数,必需把默认参数放在参数列表的最后位置! ! !
1 #content="This is a testing email" 是默认参数 2 def send(receipent,content="This is a testing email"): 3 print("Email send to:",receipent,", Content:",content) 4 print("Mail sent successfully") 5 return True 6 7 send("janice@abc-company.com") # 默认 content 用了 "This is a testing email" 8 send("janice@abc-company.com", "Company Notice") # content 用了 "Company Notice" 9 10 #Results: 11 #Email send to: janice@abc-company.com , Content: This is a testing email 12 #Mail sent successfully 13 #Email send to: janice@abc-company.com , Content: Company Notice 14 #Mail sent successfully
- 也可以声明指定参数,在调用的时候输入 “”形式参数=实际参数” e.g. content=“alex",这样就可以在函数被調用時忽略参数顺序。
- 对于动态参数有两种类: * 和 ** (分别是一个星号和两个星号)
* 一个星号: 默认将传入的参数,全部放在一个元组中。 f1(*[11,22,33,44])
** 两个星号: 默认将传入的参数,全部放在一个字典中。 f1(**{"k1":"v1","k2":"v2”})
动态参数 (*) 会返回一个元组,如果函数的形式参数有* 号就有特殊的功能 e.g. def f1(*args),就是按照顺序接受传入什么的值都会转换到元组里面,并且当做元组的一个元素;如果在传实际参数的时候加一個星 * 号 e.g. f1(*li),它的特殊的功能是将这个列表里的每一个元素都转化到元组的元素里,其实就相当于在内部做了一个 For 循环,把列表里的一个一个添加到元组里(Tuple)。
1 def f3(*args): 2 print(args) #返回一個元組 3 4 li = [11,22,"Janice","dfghjk"] 5 name = "Janice" 6 7 f3(li) 8 f3(*li) 9 f3(*"Janice") 10 f3(*name) 11 12 #Results: 13 #([11, 22, 'Janice', 'dfghjk'],) 14 #(11, 22, 'Janice', 'dfghjk') 15 #('J', 'a', 'n', 'i', 'c', 'e') 16 #('J', 'a', 'n', 'i', 'c', 'e')
动态参数 (**) 会返回一個字典,如果函数的形式参数有** 号就有特殊的功能 e.g. def f1(**args),就是传入什么的值都会转换到字典里面,并且当做字典的value;如果在传实际参数的时候加上两个星** 号e.g. f1(**dic),它的特殊的功能是将这个字典里的每一个key, value 都给转化成字典的key, value,其实就相当于直接赋值到字典里。
1 def f4(**args): 2 print(args) #返回一個字典 3 4 li = [11,22,"Janice","dfghjk"] 5 name = "Janice" 6 7 f4(n1="Janice") 8 f4(n1="Janice", n2=20) 9 10 dic = {"k1":"v1","k2":"v2"} 11 f4(kk = dic) 12 f4(**dic) 13 14 #Results 15 #{'n1': 'Janice'} 16 #{'n1': 'Janice', 'n2': 20} 17 #{'kk': {'k1': 'v1', 'k2': 'v2'}} 18 #{'k1': 'v1', 'k2': 'v2'}
-
万能参数,def f5(*args, **kwargs) (注意:* 一个星号必须在前面, ** 两个星号必须在后面!)
1 def f5(*args, **kwargs): 2 print(args) 3 print(kwargs) 4 5 f5(11,22,33,44,k1="v1",k2="v2") 6 7 #Results: 8 #(11, 22, 33, 44) 9 #{'k2': 'v2', 'k1': 'v1'}
-
全局变量和局部变量
没有写到函数体里的变量叫全局变量,它在所有文件中都是可读;在f1函数里写的变量是 f1函数私有的,叫局部变量;变量会先找自己的局部变量,然后才找全局变量,如果你想修改全局变量(重新赋值),这时需要加入一个global 的关键字+ 它的变量名。如果以后要读一个全局变量的时候,直接打印 e.g. print() 一下就可以啦!-
重点一、[列表, 字典, 元组] 如果在函数体里进行修改/新增, 这是在修改全区列表,但列表不容许在函数体里重新赋值。
- 重点二、如果是全局变量,命名时都需要大写! ! !
-
-
补充:函数的参数在传入的时候,到底是传入引用还是再传入一份列表,現在来分析一下两种结果:
- 如果传入的是一份列表,Python 在传入参数的时候是重新赋值的话,打印的时候就不应该出现 999
- 如果传入的是一个引用, li 和 a1 便会指向同一个列表
- 從运行后的结果可以总结:Python 在传参数的时候,其实是传入一个引用! ! !
1 def f7(a1): 2 a1.append(9999) 3 4 li = [11,22,33,44] 5 f7(li) 6 print(li) 7 8 #Results: 9 #[11, 22, 33, 44, 9999]
- 如果传入的是一份列表,Python 在传入参数的时候是重新赋值的话,打印的时候就不应该出现 999
实战操作
运用函数写一个简单的猜文字游戏
#!/usr/bin/env python # -*- coding: utf-8 -*- # Author: Janice Cheng import os import random import sys # make a list of words words = [ 'apple', 'banana', 'orange', 'coconuts', 'straweberry', 'lime', 'graphefruit', 'lemon', 'kumquat', 'blueberry', 'melon' ] def clear(): if os.name == 'nt': os.system('cls') else: os.system("clear") def draw(bad_guess, good_guess, secret_word): clear() print("Strikes: {}/7".format(bad_guess)) print('') for letter in bad_guess: print(letter, end=' ') print('\n\n') for letter in secret_word: if letter in good_guess: print(letter, end='') else: print('_', end='') print('') def get_guess(bad_guess, good_guess): while True: guess = input("Guess a letter: ").lower() if len(guess) != 1: print("You can only guess a single letter!") elif guess in bad_guess or guess in good_guess: print("You've already guess that letter") elif not guess.isalpha(): print("You can only guess letters!") else: return guess def play(done): clear() secret_word = random.choice(words) bad_guess = [] good_guess = [] while True: draw(bad_guess,good_guess,secret_word) guess = get_guess(bad_guess,good_guess) if guess in secret_word: good_guess.append(guess) found = True for letter in secret_word: if letter not in good_guess: found = False if found: print("You win!") print("The word was {}".format(secret_word)) done = True else: bad_guess.append(guess) if len(bad_guess) == 7: draw(bad_guess,good_guess, secret_word) print("You lost!") print("The word was {}".format(secret_word)) done = True if done: play_again = input("Play again? y/n ").lower() if play_again != 'n': return play(done=False) else: sys.exit() def welcome(): print("Welcome to Letter Guess!!") start = input("Press enter/return to start or Q to quit >> ").lower() if start == 'q': print('Bye!') sys.exit() else: return True if __name__ == "__main__": done = False while True: clear() welcome() play(done)
format 函数操作实战
ret = '{0} lives in Hong Kong for more than {1} years!!'.format('Janice',20) ret = '{name} lives in Hong Kong for more than {year} years!!'.format(name='Janice', year=20) # Janice lives in Hong Kong for more than 20 years!!
这是 Python format 函数的源码,它也是接受一个 *号的参数和 ** 两个星号的参数
def format(self, *args, **kwargs): # known special case of str.format """ S.format(*args, **kwargs) -> str Return a formatted version of S, using substitutions from args and kwargs. The substitutions are identified by braces ('{' and '}'). """ pass
- 一个 *星号的函数例子
>>> s = "My name is {} and I am {} years old".format("Janice",20) >>> s 'My name is Janice and I am 20 years old' # 在参数里加入*便可以接受列表类型 >>> s = "My name is {} and I am {} years old".format(*["Janice",20]) >>> s 'My name is Janice and I am 20 years old' # 这里不受列表类型 >>> s = "My name is {} and I am {} years old".format(["Janice",20]) Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: tuple index out of range # 在括号里定义{0}和{1},就不需要在format()函数里重覆定义传递的内容 >>> s = "My name is {0} and {0} and {0} I am {1} years old".format("Janice",20) >>> s 'My name is Janice and Janice and Janice I am 20 years old' >>> s = "My name is {} and {} and {} I am {} years old".format("Janice",21) Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: tuple index out of range
- 两个** 星号的函数例子
1 >>> s = "My name is {name} and I am {age} years old".format(name="Janice",age=20) 2 >>> s 3 4 >>> s = "My name is {name} and I am {age} years old".format(**{"name":"Janice","age":20}) # 在参数里加入**便可以接受字典类型 5 >>> s 6 'My name is Janice and I am 20 years old'
实战操作
运用函数式编程来进行登录或注册实战
[更新中...]
lambda 表达式介绍
这是一个简单的函数: f1(a) = a + 100
>>> def f1(a): ... return a + 100 ... >>> ret = f1(10) >>> print(ret) 110
lambda a: a + 100 # a + 100 是函数体,a 是变量,整句意思是输入参数 a,然后对a进行操作:a + 100
就以上的代码,可以用 lambda 表达式来实现
>>> f2 = lambda a: a + 100 #自动返回 >>> ret2 = f2(10) >>> print(ret2) 100
>>> add = lambda a1,a2: a1 + a2 #可以传两个参数 >>> add(10,10) 20
lambda 中的 filter 例子
>>> lst = [11,22,33,44] #Option1 >>> def f(x): ... return x > 22 >>> list(filter(f, lst)) [33, 44] #Option2 >>> list(filter(lambda a: a > 22, lst)) [33, 44]
lambda 中的 map 例子
>>> lst1 = [1,3,5,6,9] >>> lst2 = [2,4,6,8,10] >>> ret = map(lambda x,y: x+y, lst1, lst2) >>> list(ret) [3, 7, 11, 14, 19]
大家都应该听过 Spark,在 Spark 里用了很多 lambda 表达式来实现 filter、map、flatMap 和 reduceByKey 的功能,以下是一個 Spark 的 wordcount 例子
wordCounts = textFile.flatMap(lambda line: line.split())\ .map(lambda word: (word, 1))\ .reduceByKey(lambda a, b: a+b)
文件操作函数介紹和操作实战
打開文件
##Operation output = open(r'C:\spam', 'w') #Create output file ('w' means write) input = open('data', 'r') #Create input file ('r' means read) input = open('data') #Same as prior line ('r' is the default) open('f.txt', encoding='latin-1') #Python 3.X Unicode text files (str strings) open('f.bin', 'rb') #Python 3.X bytes files (bytes strings) open('f.bin', 'rb') #Python 2.X bytes files (str strings) for line in open('data'): #File iterators read line by line
操作文件
##Method aString = input.read() #Read entire file into a single string aString = input.read(N) #Read up to nextNcharacters (or bytes) into a string aString = input.readline() #Read next line (including\nnewline) into a string aList = input.readlines() #Read entire file into list of line strings (with \n) output.write(aString) #Write a string of characters (or bytes) into file output.writelines(aList) #Write all line strings in a list into file output.close() #Manual close (done for you when file is collected) output.flush() #Flush output buffer to disk without closing anyFile.seek(N) #Change file position to offsetNfor next operation
文件的打开方式不同就会对文件产生不同的影响,打开方式有几种:1) 以字符串类型读写文件; 2) 有加号的方式读写文件; 3) 以二进制(字节)类型读写文件;
# Remember to close the file after every file modification f = open("readme.txt",'w') #open a file for writing f.write("this is the first line\n") #write a line to the file f.write("this is the second line\n") #write one more line to the file f.close() #close a file f = open("readme.txt",'r') #open a file for reading f.read() # read the entire content of file at once f.read(1) # read 1 char from the file f.seek(1) # 调整指针到第一个位置 f.tell() f.readable() # 是否是可读文件 f.readlines() # reading all lines as an array f.readlines() # read only one line f.close() #close a file f = open("readme.txt",'a') #append data to the original file f.write("this is the third line\n") #write a line to the file f.close() #close a file
以字符串类型打开:
- Append: "a" - 以追加的方式打开文件,(打开文件后的文件指针会自动移到文件末尾) 如果文件不存在则创建。
f = open("db","a") f.write("Python") f.close() #Before: admin|123 #After: admin|123Python
- Read: "r" - 以读的方式打开文件,可读取文件信息。
1 >>> f2 = open("db","r") 2 >>> data2 = f2.read() 3 >>> print(data2) 4 Admin|123 5 Alex|alex3417 6 >>> print(type(data2)) 7 <class 'str'>
- Write: "w" - 以写的方式打开文件,如果文件存在,则清空该文件,再重新写入新内容。
1 >>> import csv 2 >>> f2 = open("db","w") 3 >>> data = "admin|123" 4 >>> f2.write(data) 5 9 6 >>> f2.close()
- Extend: "x" - 如果这个文件存在就报错,如果不存在就创建并写内容 (跟 w 是一样的,只增加多一个条件判断,判断一下当前文件是否已经存在)
1 >>> f2 = open("db","x") #如果文件已经存在,你会报错 2 Traceback (most recent call last): 3 File "<stdin>", line 1, in <module> 4 FileExistsError: [Errno 17] File exists: 'db' 5 6 >>> f2 = open("db_test","x") 7 >>> data = "admin|123" 8 >>> f2.write(data) 9 9 10 >>> f2.close()
有+號的打開模式
- Append: "a+" - 以读写方式打开文件,并把文件指针移到文件尾。
- Read: "r+" - 以读写方式打开文件,可以对文件进行读写操作,Python 在读完整个文件的时候,默认指针位置会在文件的末位,所以当 f.write("9999") 的时候,就会在文件最后的位置追加,所以如果用 "r" 打开时,可以配合 seek() 来指定写入的位置 (看下面seek()的例子)。
1 >>> f = open("db","r+", encoding='utf-8') 2 >>> data = f.read() 3 >>> print(data) 4 admin|123 5 >>> f.write("9999") 6 11 7 >>> f.close() 8 9 #Results: 10 #Before: admin|123 11 #After: admin|1239999
- Write: "w+" - 清除文件内容、然后以读写方式打开文件。可读可写,但會先清空,後再寫。
以二进制(字节)类型打开
- Append: "ab" - 如果使用二进制的方式写,必需也得传入字节类型
1 >>> f = open("db","ab") 2 >>> f.write(bytes("Python", encoding='utf-8')) 3 6 4 >>> f.close() 5 6 #Results: 7 #Before: admin|123 8 #After: admin|123Python
1 >>> f3 = open("db","ab") #如果加b只能写入字节 2 >>> f3.write("hello") 3 Traceback (most recent call last): 4 File "<stdin>", line 1, in <module> 5 TypeError: a bytes-like object is required, not 'str'
- Read: "rb" - 只读,在读文件时自己去跟Python 底层的二进制沟通,你读的时候是读二进制,所以写的时候也需要写上二进制(字节),在硬盘上存储的是二进制格式,Python 在读的时候,默认把底层的二进制字节转转换成字符串,所以打印出来才会是字符串。
1 >>> f1 = open("db","rb") 2 >>> data1 = f1.read() 3 >>> print(data1) 4 b'Admin|123\nAlex|alex3417' 5 >>> print(type(data1)) 6 <class 'bytes'>
f=open("db","r",encoding="GBK")
- Write: "wb"
文件操作的功能
- seek( ): 主动调整指针的位置,指针跳到指定位置 (永远以字符的方式找位置)
1 >>> f = open("db","r+") 2 >>> data = f.read(1) 3 >>> print(data) 4 a 5 >>> f.seek(1) #调整指针到第一个位置 6 1 7 >>> f.write("999") #当前指针位置开始向后覆盖,写数据,打开方式有 b 、只能写字节;无b就是写字符 8 3 9 >>> f.close() 10 11 #Results: 12 #Before: #admin|123 13 #After: #a999n|123
- tell( ): 获取当前指针的位置(字节),因為一個中文是3個字節,所以當調用read(1)方法之後,再查看當前字節位置,就會返回3
1 >>> f = open("db","r+") 2 >>> data = f.read(1) 3 >>> print(data) 4 金 5 >>> print(f.tell()) 6 3 7 8 #db: 金|123
- read( ): 默认无参数,读全部,如果在打开文件的时候是"rb",读取的时候会按字节;如果在打开文件的时候是"r",读取的时候会按字符。
1 >>> f = open("db","rb") 2 >>> data = f.read(1) 3 >>> print(data) 4 b'\xe9' 5 >>> f.close() 6 >>> f = open("db","r+") 7 >>> data = f.read(1) 8 >>> print(data) 9 金 10 >>> f.close()
- write( ): 写数据,如果在打开文件的时候是"rb",读取的时候会按字节;如果在打开文件的时候是"r",读取的时候会按字符。
- close( ):
- fileno( ):
- flush( ): 刷新,在文件还没有close()之前,f.write 的数据会存放在内存里而不直接写入文件,如果用了flush()的话,它就会在文件还没有调用close()的状况下强行把数据写入文件中。
1 >>> f = open("db","a") 2 >>> f.write("888") 3 3 4 >>> 5 >>> input("Please input a number: ") #等待着用户输入 6 Please input a number:
- readable( ): 判断是否可读
1 >>> f2 = open("db_test","w") 2 >>> f2.readable() 3 False 4 >>> f1 = open("db_test","r") 5 >>> f1.readable() 6 True
- seekable( ):
- readline( ): 只读取一行(读取的过程指针会在移动)
1 db.txt 2 admin|123 3 janice|janice123 4 alex|alex123 5 kennith|ken123 6 7 >>> f1 = open("db","r") 8 >>> f1.readline() 9 'admin|123\n' 10 >>> f1.readline() 11 'janice|janice123\n' 12 >>> f1.close()
- truncate( ):截断数据,只把指针位置后的清空
1 f = open("db","r+",encoding='utf-8') 2 f.seek(3) 3 f.truncate() 4 f.close() 5 6 #admin|123 7 #adm
- for-loop:
1 f = open("db","r+",encoding='utf-8') 2 for line in f: 3 print(line) 4 5 6 f.close() 7 8 #admin|123 9 #alex|alex3417 10 #kennith|ken3344
關閉文件
- close( )
f = close()
- with 文件操作
1 with open("db","r+", encoding='utf-8') as f: 2 for line in f: 3 print(line) 4 5 #admin|123 6 #alex|alex3417 7 #kennith|ken3344
- with 同時操作兩個文件
1 #從db1文件一个以只读的方法打开,從db2文件一个以只写的方法打开 2 #从DB1读一行写一行到DB2 3 with open("db1","r", encoding='utf-8') as f1, open("db2","w", encoding='utf-8') as f2: 4 for line in f1: 5 new_line = line.replace("alex","eric") 6 f2.write(new_line)
gzip
>>> import gzip >>> with gzip.open('score.csv.gz','rt') as f: ... print(f.read()) ... chinese,88 english,90 maths,85 computer science,90 chemistry,67 music,88 economics,75
本周作业
操作 haproxy.conf 文件
1 global 2 log 127.0.0.1 local2 3 daemon 4 maxconn 256 5 log 127.0.0.1 local2 info 6 defaults 7 log global 8 mode http 9 timeout connect 5000ms 10 timeout client 50000ms 11 timeout server 50000ms 12 option dontlognull 13 listen stats :8888 14 stats enable 15 stats uri /admin 16 stats auth admin:1234 17 frontend oldboy.org 18 bind 0.0.0.0:80 19 option httplog 20 option httpclose 21 option forwardfor 22 log global 23 acl www hdr_reg(host) -i www.oldboy.org 24 use_backend www.oldboy.org if www 25 backend www.oldboy.org 26 server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000 27 backend buy.oldboy.org 28 server 100.1.7.90 100.1.7.90 weight 20 maxconn 3000