-
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:
# 希望一次返回3个函数,分别计算1x1,2x2,3x3: def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count()
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:
>>> f1() 9 # 因为f1现在才计算i*i,但现在i的值已经变为3
因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
查看全部 -
Python内置的 sorted()函数可对list进行排序:
>>> sorted([36, 5, 12, 9, 21]) [5, 9, 12, 21, 36]
可以看到,sorted()函数,默认是由小到大排序列表的元素。
>>> score = [('Alice', 72), ('Candy', 90), ('Bob', 62)] >>> sorted(score) [('Alice', 72), ('Bob', 62), ('Candy', 90)]
当list的每一个元素又是一个容器时,则会以第一个元素来排序,比如在score中,每个元素都是包含名字和成绩的一个tuple,sorted()函数则按名字首字母进行了排序并返回。
如果需要按照成绩高低进行排序,需要指定排序的字段是成绩,sorted接受key参数,用来指定排序的字段,key的值是一个函数,接受待排序列表的元素作为参数,并返回对应需要排序的字段。因此,sorted()函数也是高阶函数。
def k(item): return item[1] # ==> 按成绩排序,成绩是第二个字段 sorted(score, key=k)
得到结果:[('Bob', 62), ('Alice', 72), ('Candy', 90)] 。
如果需要倒序,指定reverse参数即可。sorted(score, key=k, reverse=True)
得到结果:[('Candy', 90), ('Alice', 72), ('Bob', 62)] 。
查看全部 -
filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,并返回一个迭代器,可以迭代出所有符合条件的元素。
例如,要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数,首先,要编写一个判断奇数的函数:def is_odd(x): return x % 2 == 1
然后,利用filter()过滤掉偶数:
for item in filter(is_odd, [1, 4, 6, 7, 9, 12, 17]): print(item)
结果:1,7,9,17。
查看全部 -
reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map() 类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
在python2中,reduce()函数和map()函数一样,可以直接使用,但是在python3中,reduce()函数被收录到functools包内,需要引入functools才可以使用。
def f(x, y): return x + y
调用 reduce(f, [1, 3, 5, 7, 9]):
from functools import reduce def f(x, y): return x + y print(reduce(f, [1,3,5,7,9])) # ==> 25
reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:
print(reduce(f, [1, 3, 5, 7, 9], 100)) # ==> 125
结果将变为125,因为第一轮计算是:
计算初始值和第一个元素:f(100, 1),结果为101。
查看全部 -
map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f依次作用在list的每个元素上,map()函数会返回一个迭代器,可以依次迭代得到原来list的元素被函数f处理后的结果。
>>> map(f, list)
例如,对于list [1, 2, 3, 4, 5, 6, 7, 8, 9]。
如果希望把list的每个元素都作平方,就可以利用map()函数。
我们定义需要传入函数f(x)=x*x,就可以利用map()函数完成这个计算:def f(x): return x*x for item in map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]): print(item)
得到结果:
[1, 4, 9, 10, 25, 36, 49, 64, 81]
由于list包含的元素可以是任何类型,因此,map() 不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。
查看全部 -
服务端建立需要四个步骤:新建socket、绑定IP和端口(bind)、监听连接(listen)、接受连接(accept)。
客户端建立则简单一些,仅需两个步骤:新建socket、连接服务端(connect)。
当网络连接上以后,客户端和服务端就可以进行数据通信了,套接字通过send()函数发送数据,通过recv()函数接收数据。
先看服务端的过程,新建一个server.py的文件:import socket server = socket.socket() # 1. 新建socket server.bind(('127.0.0.1', 8999)) # 2. 绑定IP和端口(其中127.0.0.1为本机回环IP) server.listen(5) # 3. 监听连接 s, addr = server.accept() # 4. 接受连接 print('connect addr:{}'.format(addr)) content =s.recv(1024) print(str(content, encoding='utf-8')) # 接受来自客户端的消息,并编码打印出来 s.close()
如上,服务端就编写完毕,接下来是编写客户端,新建一个client.py的文件:
import socket client = socket.socket() # 1. 新建socket client.connect(('127.0.0.1', 8999)) # 2. 连接服务端(注意,IP和端口要和服务端一致) client.send(bytes('Hello World. Hello Socket', encoding='utf-8')) # 发送内容,注意发送的是字节字符串。 client.close()
接着在一个终端先运行服务端:
python server.py
然后再在另外一个终端运行客户端:
python client.py
在服务端的终端,将会输出以下信息:
connect addr:('127.0.0.1', 50382) b'Hello World. Hello Socket'
查看全部 -
为了正确关闭文件,需要考虑各种异常情况,这是非常麻烦的一件事,Python提供with关键字,可以免除这类后顾之忧。
with关键字对资源进行访问的场合,会确保不管在使用过程中是否发生异常,都会执行必要的“清理”的操作,释放资源,比如文件使用后自动关闭等等。
with的使用方法如下:with open('test.txt', 'r') as f: content = f.readlines() for line in content: print(line)
当文件使用结束后,不需要显式的调用f.close()关闭文件。
查看全部 -
Python提供文件追加内容的打开模式,可以往文件尾部添加内容,又不清空文件原有的内容。
模式
描述
a
打开一个文件并追加内容,会往文件尾部添加内容
ab
以二进制格式打开一个文件并追加内容,会往文件尾部添加内容
a+
打开一个文件并使用追加进行读写
f = open('test.txt', 'a') f.write('Hello Everyone\n') f.close()
使用a的打开方式打开文件,文件游标默认是在文件的尾部,因此,可以便捷的往文件尾部添加内容,除此以外,文件对象还提供seek()方法,可以移动文件的游标位置,它接受一个参数,表示文件的位置,0:文件首部,1:当前位置,2:文件尾部,通过seek()可以把文件游标移动到文件首部但不删除文件的内容。
f = open('test.txt', 'a+') content = f.readlines() print(content) # ==> [] f.seek(0) content = f.readlines() print(content) # ==> ['Hello World\n', 'Hello Python\n', 'Hello Imooc\n']
第一次print(content)的时候,由于文件游标在文件的尾部,所以readlines()读取不到任何数据,打印了空的结果,第二次print(content)的时候,由于通过seek(0),文件游标移动到了文件的首部,因此readlines()就返回了文件所有的内容。
查看全部 -
字符串反转可以使用切片实现: reverse = str_[::-1]
3. 换行符是'\n',字符串反转的时候,换行符也会翻转
查看全部 -
f = open('test.txt', 'w')
写入若干字符
文件对象提供write方法向文件内写入若干字符,它接受一个字符串参数,表示需要写入的字符串。
f = open('test.txt', 'w') f.write('Hello World\n') f.close()
写入若干行
文件对象提供writelines()方法向文件内容写入多行数据,它接受一个列表,表示需要写入的字符串列表。
lines = ['Hello World\n', 'Hello Python\n', 'Hello Imooc\n'] f = open('test.txt', 'w') f.writelines(lines) f.close()
查看全部 -
读取若干字符
文件对象提供read()方法,可以读取文件中的若干个字符,它提供一个参数size,可以指定读取字符的数量。
s = f.read(5) print(s) # ==> Hello
当read()之后,访问文件的游标就会移动到第六个字符前面,此时,继续read,将得到Hello后面的结果。
s = f.read(6) print(s) # ==> ' World'
读取一行
文件对象提供readline()方法,和read()方法类似,可以读取文件中的若干个字符,它也提供一个参数size,可以指定读取字符的数量,不过和read()方法不同的是,readline()方法遇到一行结束的时候,就会返回。
f.close() f = open('test.txt', 'r') # 重新打开文件 s = f.readline(20) print(s) # ==> 'Hello World.\n'
可以看到,打印的内容并没有20个字符,readline最多返回一行的所有字符。
读取多行
文件对象提供readlines()方法,可以读取多行字符,返回一个列表。它提供一个hint参数,表示指定读取的行数,没有指定则默认以列表的形式返回文件所有的字符串。
f.close() f.open('test.txt', 'r') s = f.readlines() print(s) # ==> ['Hello World.\n', 'Hello Python.\n', 'Hello Imooc.\n']
查看全部 -
除了文本以外,还有大量的非文本文件,比如图片、压缩文件、视频文件、音乐文件等等,这种文件统称为二进制文件,在Python中打开二进制文件,需要不同的打开模式。
b
二进制模式,打开二进制文件
wb
以二进制格式只写模式打开一个文件,会清除原有的内容
ab
以二进制格式打开一个文件并追加内容,会往文件尾部添加内容
rb
以二进制格式只读模式打开一个文件
f = open('test.jpg', 'rb') f.close()
查看全部 -
常用的打开模式如下:
模式
描述
t
文本模式(默认)
x
写模式,新建一个文件
b
二进制模式,打开二进制文件
+
更新一个文件(可读可写)
r
以只读模式打开一个文件
rb
以二进制格式只读模式打开一个文件
w
打开一个文件进行写入,如果文件内容已存在,会清除原有的内容
wb
以二进制格式只写模式打开一个文件,会清除原有的内容
a
打开一个文件并追加内容,会往文件尾部添加内容
ab
以二进制格式打开一个文件并追加内容,会往文件尾部添加内容
w+
打开一个文件进行读写,如果文件内容已存在,会清除原有的内容
a+
打开一个文件并使用追加进行读写
注意,为了安全操作文件,文件使用完毕后,需要使用close()函数正确关闭。
在当前目录下新建一个test.txt文件,并新建一个main.py,此时文件目录如下:|-- test.txt +-- main.py
f = open('test.txt', 'r') # 打开test.txt文件 type(f) # 打印f的类型(<class '_io.TextIOWrapper'>) f.close() # 关闭文件
查看全部 -
缩进错了就完蛋了
查看全部 -
如果需要导入自定义模块,则需要了解Python导入模块搜索的路径。
通过sys模块,可以知道导入模块的路径。>>> import sys >>> sys.path ['', '/data/miniconda3/lib/python3.8', '/data/miniconda3/lib/python3.8/site-packages']
它返回的是一个列表,表示的是在搜索Python模块时,会搜索的路径,在示例中,返回了四个路径。我们分析一些关键路径:
第一个路径是'',它是一个空字符串,表达的是当前路径的意思。
第二个路径是/data/miniconda3/lib/python3.8,它是Python默认模块的存放的路径,在这个路径下,可以发现有os、sys等模块的代码。
第三个路径是/data/miniconda3/lib/python3.8/site-packages,它是第三方模块代码的存放路径,在这个路径下,存放的是需要安装的第三方模块。那如何使用我们前面定义的tools.py模块呢?
我们在tools.py同级目录,创建main.py文件:# main.py import tools # 导入模块 tools.say_hello() # 调用模块里面的say_hello()函数 tools.say_goodbye() # 调用模块里面的say_goodbye()函数
就可以运行了。
查看全部
举报