sys模块代表了python解释器,主要用于获取和python解释器相关的信息。
[e for r in dir(sys) if not e.startswith(’_’)]
https://docs.python.org/3/library/sys.html
os模块代表了程序所在的操作系统,主要用于获取程序运行所在操作系统的相关信息。
os.__all__命令
https://docs.python.org/3/library/os.html
在os模块下还包含大量操作文件和目录的功能函数。
在os模块下与进程管理相关的函数如下。
random模块主要包含生成伪随机数的各种功能变量和函数。
random.__all__命令
https://docs.python.org/3/library/random.html
time模块主要包含各种提供日期、时间功能的类和函数。该模块既提供了把日期、时间格式化为字符串的功能,也提供了从字符串恢复日期、时间的功能。
[e for r in dir(time) if not e.startswith(’_’)]
https://docs.python.org/3/library/time.html
time.struct_time类中各属性的含义:
字段名 | 字段含义 | 值 |
---|---|---|
tm_year | 年 | 如2017、2018等 |
tm_mom | 月 | 如2、3等,范围为1~12 |
tm_mday | 日 | 如2、3等,范围为1~12 |
tm_hour | 时 | 如2、3等,范围为1~12 |
tm_min | 分 | 如2、3等,范围为1~12 |
tm_sec | 秒 | 如2、3等,范围为1~12 |
tm_wday | 周 | 周一为0,范围为0~6 |
tm_yday | 一年内第几天 | 如65,范围为1~366 |
tm_isdst | 夏令时 | 0、1或-1 |
比如,Python 可以用 time.struct_time(tm_year=2018, tm_mon=5, tm_mday=2, tm_hour=8,tm_min=0, tm_sec=30, tm_wday=3, tm_yday=1, tm_isdst=0)很清晰地代表时间。
此外,Python还可以用一个包含9个元素的元组来代表时间,该元组的9个元素和struct_time对象中9个属性的含义是一一对应的。比如程序可以使用(2018,5,2, 8,0,30,3, 1,0)来代表时商。
在日期、时间模块内常用的功能函数如下。
代码如下:
# 生命时间,假如活到90岁
import time
starttimes = (1990, 6, 23, 0, 0, 0, 0, 0, 0)
endtimes = (2080, 6, 23, 0, 0, 0, 0, 0, 0)
# 出生日期,"1990年6月23日"
starttime = time.mktime(starttimes)
# 当面时间
nowtime = time.strftime('%Y年%m年%d日 %H时%M分%S秒',time.localtime(time.time()))
# 已度时光(荒废),秒数
overtime = time.time() - starttime
# 时间尽头(90岁),"2080年6月23日"
endtime = time.mktime(endtimes)
# 剩余时间(奋斗),年、月、日、时、分、秒
# 秒
futuretimes = endtime - time.time()
# 分
futuretimeM = futuretimes//60
# 时
futuretimeh = futuretimeM//60
# 天
futuretimed = futuretimeh//24
# 周
futuretimew = futuretimed//7
# 月
futuretimem = futuretimew//4.34
# 年
futuretimey = futuretimem//12
print(nowtime)
print(overtime)
print(('%s秒') % int(futuretimes))
print(('%s分') % int(futuretimeM))
print(('%s时') % int(futuretimeh))
print(('%s天') % int(futuretimed))
print(('%s周') % int(futuretimew))
print(('%s月') % int(futuretimem))
print(('%s年') % int(futuretimey))
# 遗留问题,加单位,参考P86练习
python时间格式字符串所支持的指令
指令 | 含义 |
---|---|
%a | 本地化的星期几的缩写名,比如Sun代表星期天 |
%A | 本地化的星期几的完整名 |
%b | 本地化的月份的缩写名,比如Jan代表 一月 |
%B | 本地化的月份的完整名 |
%c | 本地化的日期和时间的表示形式 |
%d | 代表一个月中第几天的数值,范围:01~31 |
%H | 代表24小时制的小时,范围:00~23 |
%I | 代表12小时制的小时,范围:01~12 |
%j | 一年中第几天,范围:001~366 |
%m | 代表月份的数值,范围:01~12 |
%M | 代表分钟的数值,范围:00~59 |
%p | 上午或下午的本地化方式。当使用strptimeO函数并使用%1指令解析小时时,%p只影响小时字段 |
%S | 代表分钟的数值,范围:00-61,该范围确实是00~61, 60在表示闰秒的时间戮时有效,而61则是由于一些 |
历史原因造成的 | |
%U | 代表一年中第几周,以星期天为每周的第一天,范围:00~53。在这种方式下,一年中第一个星期天被认为处 |
于第一周。当使用stiptime()函数解析时间字符串时,只有同时指定了星期几和年份该指令才会有效 | |
%w | 代表星期几的数值,范围:0~6,其中0代表 |
%W | 代表一年中第儿周,以星期一为每周的第一天,范围:00-53。在这种方式下,一年中第一个星期-被认为处 |
于第一周。当使用strptime()函数解析时间字符串时,只有同时指定了星期几和年份该指令才会有效 | |
%x | 本地化的日期的表示形式 |
%X | 本地化的日期的表现形式 |
%y | 年份的缩写,范围:00~99,比如2018年就简写就好了 |
%Y | 年份的完整形式,如2018 |
%z | 显示时区偏移 |
%Z | 时区名(如果时区不存在,则显示的空) |
%% | 用于代表%符号 |
JSON是一种轻量级、跨平台、跨语言的数据交换格式,JSON格式被广泛应用于各种语言的
数据交换中。
json.__all __
JSON 的全称是 JavaScript Object Notation。
JSON主要有如下两种数据结构。
语法格式:
var a = { key1 : value1, key2: value2,…}
语法格式:
var a = [value1, value2,…]
JSON类型 | python类型 |
---|---|
对象(object) | 字典(dict) |
数组(array) | 列表(list) |
字符串(string) | 字符串(str) |
整数(number(int)) | 整数(int) |
实数(number(real)) | 浮点数(float) |
true | True |
false | False |
null | None |
python类型 | JSON类型 |
---|---|
字典(dict) | 对象(object) |
列表(list)和元组(tuple) | 数组(array) |
字符串(str) | 字符串(string) |
整数、浮点数、以及整型、浮点型派生的枚举(float,int-&float-derived Enums) | 整数(number) |
实数(number(real)) | 浮点数(float) |
True | true |
False | false |
None | null |
decode(用load或loads)
JSON字符串→python对象
encode(用dump或dumps)
python对象→JSON字符串
dumps()和dump()函数的encode操作(将Python对象转换成JSON字符串)
代码如下:
import json
# 将Python对象转JSON字符串(元组会当成数组)
s = json.dumps(['yeeku', {
'favorite': ('coding', None, 'game', 25)}])
print(s) # ["yeeku", {"favorite": ["coding", null, "game", 25]}]
# 简单的Python字符串转JSON
s2 = json.dumps("\"foo\bar")
print(s2) #"\"foo\bar"
# 简单的Python字符串转JSON
s3 = json.dumps('\\')
print(s3) #"\\"
# Python的dict对象转JSON,并对key排序
s4 = json.dumps({
"c": 0, "b": 0, "a": 0}, sort_keys=True)
print(s4) #{"a": 0, "b": 0, "c": 0}
# 将Python列表转JSON,
# 并指定JSON分隔符:逗号和冒号之后没有空格(默认有空格)
s5 = json.dumps([1, 2, 3, {
'x': 5, 'y': 7}], separators=(',', ':'))
# 输出的JSON字符串中逗号和冒号之后没有空格
print(s5) # '[1,2,3,{"4":5,"6":7}]'
# 指定indent为4,意味着转换的JSON字符串有缩进
s6 = json.dumps({
'Python': 5, 'Kotlin': 7}, sort_keys=True, indent=4)
print(s6)
# 使用JSONEncoder的encode方法将Python转JSON
s7 = json.JSONEncoder().encode({
"names": ("孙悟空", "齐天大圣")})
print(s7) # {"names": ["\u5b59\u609f\u7a7a", "\u9f50\u5929\u5927\u5723"]}
f = open('a.json', 'w')
# 使用dump()函数将转换得到JSON字符串输出到文件
json.dump(['Kotlin', {
'Python': 'excellent'}], f)
sort_keys:排序,(sort_keys=True)
indent:缩进,(indent=4)
separators:没有空格(separators=(’,’, ‘:’))
loads()和load()函数的decode操作(将JSON字符串转换成Python对象)。
代码如下:
import json
# 将JSON字符串恢复成Python列表
result1 = json.loads('["yeeku", {"favorite": ["coding", null, "game", 25]}]')
print(result1) # ['yeeku', {'favorite': ['coding', None, 'game', 25]}]
# 将JSON字符串恢复成Python字符串
result2 = json.loads('"\\"foo\\"bar"')
print(result2) # "foo"bar
# 定义一个自定义的转化函数
def as_complex(dct):
if '__complex__' in dct:
return complex(dct['real'], dct['imag'])
return dct
# 使用自定义的恢复函数
# 自定义回复函数将real数据转成复数的实部,将imag转成复数的虚部
result3 = json.loads('{"__complex__": true, "real": 1, "imag": 2}',\
object_hook=as_complex)
print(result3) # (1+2j)
f = open('a.json')
# 从文件流恢复JSON列表
result4 = json.load(f)
print(result4) # ['Kotlin', {'Python': 'excellent'}]
正则表达式(Regular Expression)用于描述一种字符串匹配的模式(Pattern),它可用于检査一个字符串是否含有某个子串,也可用于从字符串中提取匹配的子串,或者对字符串中匹配的子串执行替换操作。
re.__all __
该函数用于将正则表达式字符串编译成_sre.SRE_Pattem对象,该对象代表了正则表达式编译之后在内存中的对象,它可以缓存并/用正则尾达式字符串。如果程序需要多次使用同一个正则表达式字符串,则可考虑先编译它。
该函数的partem参数就是它所编译的正则表达式字符串,flags则代表了正则表达式的匹配旗
标。
尝试从字符串的开始位置来匹配正则表达式,如果从开始
位置匹配不成功,match。函数就返回None。其中pattern参数代表正则表达式;string代表
被匹配的字符串;flags则代表正则表达式的匹配旗标。该函数返回_sre.SRE_Match对象,
该对象包含的span(n)方法用于获取第n+1个组的匹配位置,group(n)方法用于获取第n+1
个组所匹配的子串。
扫描整个字符串,并返回字符串中第一处匹配pattern的
匹配对象。其中pattern参数代表正则表达式:string代表被匹配的字符串:flags则代表正
则表达式的匹配旗标。该函数也返回sre.SRE Match对象。
match()与search()的区别在于:match()必须从字符串开始处就匹配,
但search()则可以搜索整个字符串。
span()、group()
代码如下:
import re
m1 = re.match('www', 'www.fkit.org')# 开始位置可以匹配
print(m1.span()) # span返回匹配的位置
print(m1.group()) # group返回匹配的组
print(re.match('fkit', 'www.fkit.com')) # 开始位置匹配不到,返回None
m2 = re.search('www', 'www.fkit.org') # 开始位置可以匹配
print(m2.span())
print(m2.group())
m3 = re.search('fkit', 'www.fkit.com') # 中间位置可以匹配,返回Match对象
print(m3.span())
print(m3.group())
>> (0, 3)
>> WWW
>> None
>> (0, 3)
>> WWW
>> (4, 8)
>> fkit
扫描整个字符串,并返回字符串中所有匹配pattern的子
串组成的列表。其中pattern参数代表正则表达式;string代表被匹配的字符串;flags则代
表正则表达式的匹配旗标。
扫描整个字符串,并返回字符串中所有匹配pattern的子
串组成的迭代器,迭代器的元素是_sre.SRE_Match对象。其中pattern参数代表正则表达式;
string代表被匹配的字符串;flags则代表正则表达式的匹配旗标。
findall()与finditer()函数的功能基本相似,区别在于它们的返回值不同,
findall()函数返回所有匹配patten的子串组成的列表;而finditer()函数则返回所有匹配pattern的子
串组成的迭代器。
如果对比findall(), finditer()和search()函数,它们的区别也很明显,search。只返回字符串中第
一处匹配pattern的子串;而findall()和finditer()则返回字符串中所有匹配pattern的子串。
re.I、span()、group()
代码如下:
import re
# 返回所有匹配pattern的子串组成的列表, 忽略大小写
print(re.findall('fkit', 'FkIt is very good , Fkit.org is my favorite' , re.I))
# 返回所有匹配pattern的子串组成的迭代器, 忽略大小写
it = re.finditer('fkit', 'FkIt is very good , Fkit.org is my favorite' , re.I)
for e in it:
print(str(e.span()) + "-->" + e.group())
>> ['FkIt', 'Fkit']
>> 0-->FkIt
>> 20-->Fkit
该函数要求整个字符串能匹配pattern,如果匹配则返
回包含匹配信息的一sre.SRE_Match对象;否则返回None。
该函数用于将 string 字符串中所有匹配 pattern
的内容替换成repl; repl既可是被替换的字符串,也可是一个函数。count参数控制最多替
换多少次,如果指定count为0,则表示全部替换。
代码如下:
import re
my_date = '2020-02-12'
# 将my_date字符串里中画线替换成斜线
print(re.sub(r'-', '/' , my_date))
# 将my_date字符串里中画线替换成斜线,只替换一次
print(re.sub(r'-', '/' , my_date, 1))
>> 2020/02/12
>> 2020/02-12
# 在匹配的字符串前后添加内容
def fun(matched):
# matched就是匹配对象,通过该对象的group()方法可获取被匹配的字符串
value = "《疯狂" + (matched.group('lang')) + "讲义》"
return value
s = 'Python很好,Kotlin也很好'
# 将s里面的英文单词(用re.A旗标控制)进行替换
# 使用fun函数指定替换的内容
print(re.sub(r'(?P\w+)' , fun, s, flags=re.A))
>> 《疯狂Python讲义》很好,《疯狂Kotlin讲义》也很好
由于此时还未深入介绍正则表达式的语法,因此前面所使用的正则表达式都很简单,但此处使
用了一个稍微复杂的正则表达式:r’(?P < lang > \w+)'。
r’(?P < lang > \w+)'正则表达式用圆括号表达式创建了一个组,并使用“?P”选项为该组起名为
lang——所起的组名要放在尖括号内。剩下的“\w+”才是正则表达式的内容,其中“\w”代表任
意字符;"+”用于限定前面的“\w”可出现一次到多次,因此“\w+”代表一个或多个任意字符。
又由于程序执行sub()函数时指定了 re.A选项,这样“\w”就只能代表ASCII字符,不能代表汉字。
当使用sub()函数执行替换时,正则表达式“\w+”所匹配的内容可以通过组名“lang”来获取,
这样fun()函数就调用了 matched.group(‘lang’)来获取"\w+"所匹配的内容。
使用 pattern 对 string 进行分割,该函数返回分
割得到的多个子串组成的列表。其中maxsplit参数控制最多分割几次。
代码如下:
import re
# 使用逗号对字符串进行分割
print(re.split(', ', 'fkit, fkjava, crazyit'))
# 输出:['fkit', 'fkjava', 'crazyit']
# 指定只分割1次,被切分成2个子串
print(re.split(', ', 'fkit, fkjava, crazyit', 1))
# 输出:['fkit', 'fkjava, crazyit']
# 使用a进行分割
print(re.split('a', 'fkit, fkjava, crazyit'))
# 输出:['fkit, fkj', 'v', ', cr', 'zyit']
# 使用x进行分割,没有匹配内容,则不会执行分割
print(re.split('x', 'fkit, fkjava, crazyit'))
# 输出:['fkit, fkjava, crazyit']
#print(re.split('\W+', ' runoob, runoob, runoob.'))
#['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
#re.split('\W+', ' runoob, runoob, runoob.', 1)
#['', 'runoob, runoob, runoob.']
#>>> re.split('a*', 'hello world') # 对于一个找不到匹配的字符串而言,split 不会对其作出分割
#['hello world']
清除正则表达式缓存。
对模式中除ASCII字符、数值、下画线(_)之外的其他字符进行转义。
代码如下:
import re
# 对模式中特殊字符进行转义
print(re.escape(r'www.crazyit.org is good, i love it!'))
# 输出:www\.crazyit\.org\ is\ good\,\ i\ love\ it\!
print(re.escape(r'A-Zand0-9?'))
# 输出:A\-Zand0\-9\?
import re
# 编译得到正则表达式对象
pa = re.compile('fkit')
# 调用match方法,原本应该从开始匹配,
# 此处指定从索引为4的地方开始匹配,就可以成功匹配了
print(pa.match('www.fkit.org', 4).span()) # (4, 8)
# 此处指定从索引为4到索引6之间执行匹配,匹配失败
print(pa.match('www.fkit.org', 4, 6)) # None
# 此处指定从索引为4到索引8之间执行全匹配,匹配成功
print(pa.fullmatch('www.fkit.org', 4, 8).span()) # (4, 8)
_sre.SRE Match对象包含了如下方法或属性。
import re
# 在正则表达式中使用组
m = re.search(r'(fkit).(org)', r"www.fkit.org is a good domain")
print(m.group(0)) # fkit.org
# 调用简化写法,底层是调用m.__getitem__(0)
print(m[0]) # fkit.org
print(m.span(0)) # (4, 12)
print(m.group(1)) # fkit
# 调用简化写法,底层是调用m.__getitem__(1)
print(m[1]) # fkit
print(m.span(1)) # (4, 8)
print(m.group(2)) # org
# 调用简化写法,底层是调用m.__getitem__(2)
print(m[2]) # org
print(m.span(2)) # (9, 12)
# 返回所有组所匹配的字符串组成的元组
如果在正则表达式中为组指定了名字(用?P〈名字〉为正则表达式的组指定名字),就可以调用
groupdict()方法来获取所有组所匹配的字符串组成的字典一其中组名作为字典的key。例如如下
代码。
代码如下:
# 为正则表达式定义了两个组,并为组指定了名字
m2 = re.search(r'(?Pfkit).(?Porg)' ,\
r"www.fkit.org is a good domain")
print(m2.groupdict()) # {'prefix'1: 'fkit', 'suffix': 'org'}
>> {
'prefix': 'fkit', 'suffix': 'org'}
字符 | 解释 |
---|---|
x | 字符x(x可代表任意合法的字符) |
\uhhhh | 十六进制值0xhhhh所表示的Unicode字符 |
\t | 制表符(’\u0009’) |
\n | 新行(换行)符(’\u000A’) |
\r | 回车符(’\u000D’) |
\f | 换页符(’\u000C’) |
\a | 报警(bell)符(’\u0007’) |
\e | Escape符(’\u001B’) |
\cx | x对应的控制符。例如,\cM匹配 |
特殊字符 | 说明 |
---|---|
$ | 匹配一行的结尾。要匹配 $ 字符本身,请使用 \ $ |
^ | 匹配一行的开头。要匹配 ^ 字符本身,请使用 \ ^ |
( ) | 标记子表达式(也就是组)的开始位置和结束位置。要匹配这些字符,请使用\(和\) |
[ ] | 用于确定中括号表达式的开始位置和结束位置。要匹配这些字符,请使用 \ [ 和 \ ] |
{ } | 用于标记前面子表达式的出现频度。要匹配这些字符,请使用 \ {和 \ } |
* | 指定前面子表达式可以出现零次或多次。要匹配 * 字符本身,请使用 \ * |
+ | 指定前面子表达式可以出现一次或多次。要匹配+字符本身,请使用 \ + |
? | 指定前面子表达式可以出现零次或一次。要匹配?字符本身,请使用 \ ? |
. | 匹配除换行符\n之外的任意单个字符。要匹配・字符本身,请使用 \ . |
\ | 用于转义下一个字符,或指定八进制、十六进制字符。如果需匹配\字符,请使用 \ \ |
l | 指定在两项之间任选一项。如果要匹配I字符本身.请使用\ l |
预定义字符 | 说明 |
---|---|
. | 默认可匹配除换行符之外的任意字符,在使用re.S或S.DOTALL旗标之后,它还可匹配换行符 |
\d | 匹配0~9的所有数字 |
\D | 匹配非数字 |
\s | 匹配所有的空白字符,包括空格、制表符、回车符、换页符、换行符等 |
\S | 匹配所有的非空白字符 |
\w | 匹配所有的单词字符,包括0〜9的所有数字、26个英文字母和下画线(_) |
\W | 匹配所有的非单词字符 |
方括号表达式 | 说明 |
---|---|
表示枚举 | 例如[abc],表示a、b、c其中任意一个字符;[gz],表示g、z其中任意一个字符 |
表示范围 | 例如[a・f],表示a~f范围内的任意字符;[\u0041-\u0056],表示十六进制字符\u0041到\u0056 |
范围的字符。范围可以和枚举结合使用,如[a-cx-z],表示a~c、x〜z范围内的任意字符 | |
表示求否:^ | 例如[^abc],表示非a、b、c的任意字符:[ ^ a-f ],表示不是a〜f范围内的任意字符 |
边界匹配符 | 说明 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词的边界,即只能匹配单词前后的空白 |
\B | 非单词的边界,即只能匹配不在单词前后的空白 |
\A | 只匹配字符串的开头 |
\Z | 只匹配字符串的结尾,仅用于最后的结束符 |
代码如下:
>>> print (re.fullmatch (r'\u0041\\', 'A\\')) # 匹配 A\
<_sre.SREMatch object; span=(0, 2), match='A\\'>
>>> print(re.fullmatch (r'\u0061\t', 'a\t')) # 匹配 a< 制表符〉
<_sre.SRE_Match object; span=(0, 2), match='a\t'>
>>> print(re.fullmatch (r'\?\ [', '?[')) # // 匹配?[
<_sre.SRE_Match object; span=(0, 2), match='?['>
>>> re.fullmatch (r'c\wt', 'cat') # c\wt 可以匹配 cat、cbt、cct、cOt、c9t 等一批字符串
<_sre.SRE_Match object; span=(O, 3), match='cat'>
>>> re.fullmatch (r'c\wt', 'c9t') # c\wt 可以匹配 cat、cbt、cct、cOt、c9t 等一批字符串
<_sre.SRE_Match object; span=(0, 3), match='c9t'>
# 匹配如000-000-0000形式的电话号码
>>> re.fullmatch(r'\d\d\d-\d\d\d-\d\d\d\d' , '123-456-8888')
<_sre.SRE_Match object; span=(0, 12), match='123-456-8888'>
正则表达式还支持圆括号表达式,用于将多个表达式组成一个子表达式,在圆括号中可以使用
或运算符(|)。圆括号表达式也是功能丰富的用法之一。
子表达式(组)支持如下用法。
Python正则表达式支持如下几种频度限定。
000-000-000,可写成r’\d{3}-\d{3}-\d{4}
deque则代表一个双端队列。双端队列的特征是它的两端都可以添加、删除元素,它既可作为
栈(stack)使用,也可作为队列(queue)使用。
set集合有如下两个特征:
[e for e in dir(set) if not e.startswith(’_’))],查看方法
代码如下:
# 使用花括号构建set集合
c = {
'白骨精'}
# 添加元素
c.add("孙悟空")
c.add(6)
print("c集合的元素个数为:" , len(c)) # 输出3
# 删除指定元素
c.remove(6)
print("c集合的元素个数为:" , len(c)) # 输出2
# 判断是否包含指定字符串
print("c集合是否包含'孙悟空'字符串:" , ("孙悟空" in c)) # 输出True
c.add("轻量级Java EE企业应用实战")
print("c集合的元素:" , c)
# 使用set()函数(构造器)来创建set集合
books = set()
books.add("轻量级Java EE企业应用实战")
books.add("疯狂Java讲义")
print("books集合的元素:" , books)
# issubset()方法判断是否为子集合
print("books集合是否为c的子集合?", books.issubset(c)) # 输出False
# issubset()方法与<=运算符效果相同
print("books集合是否为c的子集合?", (books <= c)) # 输出False
# issuperset()方法判断是否为父集合
# issubset和issuperset其实就是倒过来判断
print("c集合是否完全包含books集合?", c.issuperset(books)) # 输出False
# issuperset()方法与>=运算符效果相同
print("c集合是否完全包含books集合?", (c >= books)) # 输出False
# 用c集合减去books集合里的元素,不改变c集合本身
result1 = c - books
print(result1)
# difference()方法也是对集合做减法,与用-执行运算的效果完全一样
result2 = c.difference(books)
print(result2)
# 用c集合减去books集合里的元素,改变c集合本身
c.difference_update(books)
print("c集合的元素:" , c)
# 删除c集合里的所有元素
c.clear()
print("c集合的元素:" , c)
# 直接创建包含元素的集合
d = {
"疯狂Java讲义", '疯狂Python讲义', '疯狂Kotlin讲义'}
print("d集合的元素:" , d)
# 计算两个集合的交集,不改变d集合本身
inter1 = d & books
print(inter1)
# intersection()方法也是获取两个集合的交集,与用&执行运算的效果完全一样
inter2 = d.intersection(books)
print(inter2)
# 计算两个集合的交集,改变d集合本身
d.intersection_update(books)
print("d集合的元素:" , d)
# 将range对象包装成set集合
e = set(range(5))
f = set(range(3, 7))
print("e集合的元素:" , e)
print("f集合的元素:" , f)
# 对两个集合执行异或运算
xor = e ^ f
print('e和f执行xor的结果:', xor)
# 计算两个集合的并集,不改变e集合本身
un = e.union(f)
print('e和f执行并集的结果:', un)
# 计算两个集合的并集,改变e集合本身
e.update(f)
print('e集合的元素:', e)
set集合支持的运算符:
frozenset的作用主要有两点。
在“数据结构"课程中最常讲授的数据结构有栈、队列、双端队列。
栈是一种后进先出(LIFO)的线性表。
队列是一种先进先出(FIFO)的线性表。
双端队列(即此处介绍的deque)代表一种特殊的队列,它可以在两端同时进行插入、删除操作。
deque位于collections包下,在交互式解释器中先导入collections包,然后输入[e for e in
dir(collections.deque) if not e.startswith(’_’)命令来査看deque的全部方法。
代码如下:
from collections import deque
stack = deque(('Kotlin', 'Python'))
# 元素入栈
stack.append('Erlang')
stack.append('Swift')
print('stack中的元素:' , stack)
# 元素出栈,后添加的元素先出栈
print(stack.pop())
print(stack.pop())
print(stack)
heapq.__all __
代码如下:
from heapq import *
my_data = list(range(10))
my_data.append(0.5)
# 此时my_data依然是一个list列表
print('my_data的元素:', my_data)
# 对my_data应用堆属性
heapify(my_data)
print('应用堆之后my_data的元素:', my_data)
heappush(my_data, 7.2)
print('添加7.2之后my_data的元素:', my_data)
# 弹出堆中最小的元素
print(heappop(my_data)) # 0
print(heappop(my_data)) # 0.5
print('弹出两个元素之后my_data的元素:', my_data)
# 弹出最小元素,压入指定元素
print(heapreplace(my_data, 8.1))
print('执行replace之后my_data的元素:', my_data)
print('my_data中最大的3个元素:', nlargest(3, my_data))
print('my_data中最小的4个元素:', nsmallest(4, my_data))
ChainMap是一个方便的工具类,它使用链的方式将多个dict “链”在一起,从而允许程序可
直接获取任意一个diet所包含的key对应的value。(有重复的key)
代码如下:
from collections import ChainMap
# 定义3个dict对象
a = {
'Kotlin': 90, 'Python': 86}
b = {
'Go': 93, 'Python': 92}
c = {
'Swift': 89, 'Go': 87}
# 将3个dict对象链在一起,就像变成了一个大的dict
cm = ChainMap(a, b , c)
print(cm)
# 获取Kotlin对应的value
print(cm['Kotlin']) # 90
# 获取Python对应的value
print(cm['Python']) # 86
# 获取Go对应的value
print(cm['Go']) # 93
可以自动统计容器中各元素出现的次数。
代码如下:
from collections import Counter
# 创建空的Counter对象
c1 = Counter()
# 以可迭代对象创建Counter对象
c2 = Counter('hannah')
print(c2)
# 以可迭代对象创建Counter对象
c3 = Counter(['Python', 'Swift', 'Swift', 'Python', 'Kotlin', 'Python'])
print(c3)
# 以dict来创建Counter对象
c4 = Counter({
'red': 4, 'blue': 2})
print(c4)
# 使用关键字参数的语法创建Counter
c5 = Counter(Python=4, Swift=8)
print(c5)
代码如下:
from collections import Counter
# 创建Counter对象
cnt = Counter()
# 访问并不存在的key,将输出该key的次数为0.
print(cnt['Python']) # 0
for word in ['Swift', 'Python', 'Kotlin', 'Kotlin', 'Swift', 'Go']:
cnt[word] += 1
print(cnt)
# 只访问Counter对象的元素
print(list(cnt.elements()))
# 将字符串(迭代器)转换成Counter
chr_cnt = Counter('abracadabra')
# 获取出现最多的3个字母
print(chr_cnt.most_common(3)) # [('a', 5), ('b', 2), ('r', 2)]
c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
# 用Counter对象执行减法,其实就是减少各元素的出现次数
c.subtract(d)
print(c) # Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
e = Counter({
'x': 2, 'y': 3, 'z': -4})
# 调用del删除key-value对,会真正删除该key-value对
del e['y']
print(e)
# 访问'w'对应的value,'w'没有出现过,因此返回0
print(e['w']) # 0
# 删除e['w'],删除该key-value对
del e['w']
# 再次访问'w'对应的value,'w'还是没有,因此返回0
print(e['w']) # 0
Counter执行各种运算的含义如下。
代码如下:
from collections import Counter
# 创建Counter对象
c = Counter(Python=4, Swift=2, Kotlin=3, Go=-2)
# 统计Counter中所有出现次数的总和
print(sum(c.values())) # 7
# 将Counter转换为list,只保留各key
print(list(c)) # ['Python', 'Swift', 'Kotlin', 'Go']
# 将Counter转换为set,只保留各key
print(set(c)) # {'Go', 'Python', 'Swift', 'Kotlin'}
# 将Counter转换为dict
print(dict(c)) # {'Python': 4, 'Swift': 2, 'Kotlin': 3, 'Go': -2}
# 将Counter转换为list,列表元素都是(元素, 出现次数)组
list_of_pairs = c.items()
print(list_of_pairs) # dict_items([('Python', 4), ('Swift', 2), ('Kotlin', 3), ('Go', -2)])
# 将列表元素为(元素, 出现次数)组的list转换成Counter
c2 = Counter(dict(list_of_pairs))
print(c2) # Counter({'Python': 4, 'Kotlin': 3, 'Swift': 2, 'Go': -2})
# 获取Counter中最少出现的3个元素
print(c.most_common()[:-4:-1]) # [('Go', -2), ('Swift', 2), ('Kotlin', 3)]
# 清空所有key-value对
c.clear()
print(c) # Counter()
c = Counter(a=3, b=1, c=-1)
d = Counter(a=1, b=-2, d=3)
# 对Counter执行加法
print(c + d) # Counter({'a': 4, 'd': 3})
# 对Counter执行减法
print(c - d) # Counter({'b': 3, 'a': 2})
Counter({
'a': 2})
# 对Counter执行交运算
print(c & d) # Counter({'a': 1})
print(c | d) # Counter({'a': 3, 'd': 3, 'b': 1})
print(+c) # Counter({'a': 3, 'b': 1})
print(-d) # Counter({'b': 2})
defaultdict是diet的子类,因此defaultdict也可被当成diet来使用,diet支持的功能,defaultdict
基本都支持。但它与diet最大的区别在于:如果程序试图根据不存在的key来访问diet中对应的
value,则会引发KeyError异常:而defaultdict则可以提供—个default_factory属性,该属性所指定
的函数负责为不存在的key来生成value。
代码如下:
from collections import defaultdict
s = [('Python', 1), ('Swift', 2), ('Python', 3), ('Swift', 4), ('Python', 9)]
# 创建defaultdict,设置由list()函数来生成默认值
d = defaultdict(list)
for k, v in s:
# 直接访问defaultdict中指定key对应的value即可。
# 如果该key不存在,defaultdict会自动为该key生成默认值
d[k].append(v)
print(list(d.items()))
>> [('Python', [1, 3, 9]), ('Swift', [2, 4])]
namedtuple。是一个工厂函数,使用该函数可以创建一个tuple类的子类,该子类可以为tuple
的每个元素都指定字段名,这样程序就可以根据字段名来访问namedtuple的各元素了。当然,如
果有需要,程序依然可以根据索引来访问namedtuple的各元素。
namedtuple是轻量级的,性能很好,其并不比普通tuple需要更多的内存。
语法格式如下:
namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)
参数说明如下:
代码如下:
from collections import namedtuple
# 定义命名元组类:Point
Point = namedtuple('Point', ['x', 'y'])
# 初始化Point对象,即可用位置参数,也可用命名参数
p = Point(11, y=22)
# 像普通元组一样用根据索引访问元素
print(p[0] + p[1]) # 33
# 执行元组解包,按元素的位置解包
a, b = p
print(a, b) # 11, 22
# 根据字段名访问各元素
print(p.x + p.y) # 33
print(p) # Point(x=11, y=22)
my_data = ['East', 'North']
# 创建命名元组对象
p2 = Point._make(my_data)
print(p2) # Point(x='East', y='North')
# 将命名元组对象转换成OrderedDict
print(p2._asdict()) # OrderedDict([('x', 'East'), ('y', 'North')])
# 替换命名元组对象的字段值
p2._replace(y='South')
print(p2) # Point(x='East', y='North')
# 输出p2包含的所有字段
print(p2._fields) # ('x', 'y')
# 再次定义一个命名元组类
Color = namedtuple('Color', 'red green blue')
# 再次定义命名元组类,其字段由Point的字段加上Color的字段
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
# 创建Pixel对象,分别为x、y、red、green、blue字段赋值
pix = Pixel(11, 22, 128, 255, 0)
print(pix) # Pixel(x=11, y=22, red=128, green=255, blue=0)
为命名元组提供了如下方法和属性。
OrderedDict也是diet的子类,其最大特征是:它可以“维护”添加key-value对的顺序。简单
来说,就是先添加的key-value对排在前面,后添加的key-value对排在后面。
由于OrderedDict能维护key-value对的添加顺序,因此即使两个OrderedDict中的key-value
对完全相同,但只要它们的顺序不同,程序在判断它们是否相等时也依然会返回false。
代码如下:
from collections import OrderedDict
# 创建OrderedDict对象
dx = OrderedDict(b=5, c=2, a=7)
print(dx) # OrderedDict([('b', 5), ('c', 2), ('a', 7)])
d = OrderedDict()
# 向OrderedDict中添加key-value对
d['Python'] = 89
d['Swift'] = 92
d['Kotlin'] = 97
d['Go'] = 87
# 遍历OrderedDict的key-value对
for k,v in d.items():
print(k, v)
# 创建普通的dict对象
my_data = {
'Python': 20, 'Swift':32, 'Kotlin': 43, 'Go': 25}
# 创建基于key排序的OrderedDict
d1 = OrderedDict(sorted(my_data.items(), key=lambda t: t[0]))
# 创建基于value排序的OrderedDict
d2 = OrderedDict(sorted(my_data.items(), key=lambda t: t[1]))
print(d1) # OrderedDict([('Go', 25), ('Kotlin', 43), ('Python', 20), ('Swift', 32)])
print(d2) # OrderedDict([('Python', 20), ('Go', 25), ('Swift', 32), ('Kotlin', 43)])
print(d1 == d2) # False
代码如下:
from collections import OrderedDict
d = OrderedDict.fromkeys('abcde')
# 将b对应的key-value对移动到最右边(最后加入)
d.move_to_end('b')
print(d.keys()) # odict_keys(['a', 'c', 'd', 'e', 'b'])
# 将b对应的key-value对移动到最左边(最先加入)
d.move_to_end('b', last=False)
print(d.keys()) # odict_keys(['b', 'a', 'c', 'd', 'e'])
# 弹出并返回最右边(最后加入)的key-value对
print(d.popitem()[0]) # e
# 弹出并返回最左边(最先加入)的key-value对
print(d.popitem(last=False)[0]) # b
[ e for e in dir(itertools) if not e.startswith(’_’)]
迭代器
代码如下:
import itertools as it
# count(10, 3)生成10、13、16……迭代器
for e in it.count(10, 3):
print(e)
# 用于跳出无限循环
if e > 20:
break
print('---------')
my_counter = 0
# cycle用于对序列生成无限循环的迭代器
for e in it.cycle(['Python', 'Kotlin', 'Swift']):
print(e)
# 用于跳出无限循环
my_counter += 1
if my_counter > 7:
break
print('---------')
# repeat用于生成n个元素重复的迭代器
for e in it.repeat('Python', 3):
print(e)
代码如下:
import itertools as it
# 默认使用累加的方式计算下一个元素的值
for e in it.accumulate(range(6)):
print(e, end=', ') # 0, 1, 3, 6, 10, 15
print('\n---------')
# 使用x*y的方式来计算迭代器下一个元素的值
for e in it.accumulate(range(1, 6), lambda x, y: x * y):
print(e, end=', ') # 1, 2, 6, 24, 120
print('\n---------')
# 将两个序列“链”在一起,生成新的迭代器
for e in it.chain(['a', 'b'], ['Kotlin', 'Swift']):
print(e, end=', ') # 'a', 'b', 'Kotlin', 'Swift'
print('\n---------')
# 根据第二个序列来筛选第一个序列的元素,
# 由于第二个序列只有中间两个元素为1(True),因此前一个序列只保留中间两个元素
for e in it.compress(['a', 'b', 'Kotlin', 'Swift'], [0, 1, 1, 0]):
print(e, end=', ') # 只有: 'b', 'Kotlin'
print('\n---------')
# 获取序列中从长度不小于4的元素开始、到结束的所有元素
for e in it.dropwhile(lambda x:len(x)<4, ['a', 'b', 'Kotlin', 'x', 'y']):
print(e, end=', ') # 只有: 'Kotlin', 'x', 'y'
print('\n---------')
# 去掉序列中从长度不小于4的元素开始、到结束的所有元素
for e in it.takewhile(lambda x:len(x)<4, ['a', 'b', 'Kotlin', 'x', 'y']):
print(e, end=', ') # 只有: 'a', 'b'
print('\n---------')
# 只保留序列中从长度不小于4的元素
for e in it.filterfalse(lambda x:len(x)<4, ['a', 'b', 'Kotlin', 'x', 'y']):
print(e, end=', ') # 只有: 'Kotlin'
print('\n---------')
# 使用pow函数对原序列的元素进行计算,将计算结果作为新序列的元素
for e in it.starmap(pow, [(2,5), (3,2), (10,3)]):
print(e, end=', ') # 32, 9, 1000
print('\n---------')
# 将'ABCD'、'xy'的元素按索引合并成元组,这些元组作为新序列的元素
# 长度不够的序列元素使用'-'字符代替
for e in it.zip_longest('ABCD', 'xy', fillvalue='-'):
print(e, end=', ') # ('A', 'x'), ('B', 'y'), ('C', '-'), ('D', '-')
>> 0, 1, 3, 6, 10, 15,
>> ---------
>> 1, 2, 6, 24, 120,
>> ---------
>> a, b, Kotlin, Swift,
>> ---------
>> b, Kotlin,
>> ---------
>> Kotlin, x, y,
>> ---------
>> a, b,
>> ---------
>> Kotlin,
>> ---------
>> 32, 9, 1000,
>> ---------
>> ('A', 'x'), ('B', 'y'), ('C', '-'), ('D', '-'),
排列组合
代码如下:
import itertools as it
# 使用两个序列进行排列组合
for e in it.product('AB', 'CD'):
print(''.join(e), end=', ') # AC, AD, BC, BD,
print('\n---------')
# 使用一个序列、重复2次进行全排列
for e in it.product('AB', repeat=2):
print(''.join(e), end=', ') # AA, AB, BA, BB,
print('\n---------')
# 从序列中取2个元素进行排列
for e in it.permutations('ABCD', 2):
print(''.join(e), end=', ') # AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC,
print('\n---------')
# 从序列中取2个元素进行组合、元素不允许重复
for e in it.combinations('ABCD', 2):
print(''.join(e), end=', ') # AB, AC, AD, BC, BD, CD,
print('\n---------')
# 从序列中取2个元素进行组合、元素允许重复
for e in it.combinations_with_replacement('ABCD', 2):
print(''.join(e), end=', ') # AA, AB, AC, AD, BB, BC, BD, CC, CD, DD,
[ e for e in dir(functools) if not e.startswith(’_’)]
代码如下:
from functools import *
# 以初始值(默认为0)为x,以当前序列元素为y,x+y的和作为下一次的初始值
print(reduce(lambda x,y: x + y, range(5))) # 10
print(reduce(lambda x,y: x + y, range(6))) # 15
# 设初始值为10
print(reduce(lambda x,y: x + y, range(6), 10)) # 25
print('----------------')
class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'User[name=%s' % self.name
# 定义一个老式的大小比较函数,User的name越长,该User越大
def old_cmp(u1 , u2):
return len(u1.name) - len(u2.name)
my_data = [User('Kotlin'), User('Swift'), User('Go'), User('Java')]
# 对my_data排序,需要关键字参数(调用cmp_to_key将old_cmp转换为关键字参数
my_data.sort(key=cmp_to_key(old_cmp))
print(my_data)
print('----------------')
@lru_cache(maxsize=32)
def factorial(n):
print('~~计算%d的阶乘~~' % n)
if n == 1:
return 1
else:
return n * factorial(n - 1)
# 只有这行会计算,然后会缓存5、4、3、2、1的解乘
print(factorial(5))
print(factorial(3))
print(factorial(5))
print('----------------')
# int函数默认将10进制的字符串转换为整数
print(int('12345'))
# 为int函数的base参数指定参数值
basetwo = partial(int, base=2)
basetwo.__doc__ = '将二进制的字符串转换成整数'
# 相当于执行base为2的int()函数
print(basetwo('10010'))
print(int('10010', 2))
partialmethod
代码如下:
from functools import *
class Cell:
def __init__(self):
self._alive = False
# @property装饰器指定该方法可使用属性语法访问
@property
def alive(self):
return self._alive
def set_state(self, state):
self._alive = bool(state)
# 指定set_alive()方法就是将set_state()方法的state参数指定为True
set_alive = partialmethod(set_state, True)
# 指定set_dead()方法就是将set_state()方法的state参数指定为False
set_dead = partialmethod(set_state, False)
c = Cell()
print(c.alive)
# 相当于调用c.set_state(True)
c.set_alive()
print(c.alive)
# 相当于调用c.set_state(False)
c.set_dead()
print(c.alive)
total_ordering
代码如下:
from functools import *
@total_ordering
class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'User[name=%s' % self.name
# 根据是否有name属性来决定是否可比较
def _is_valid_operand(self, other):
return hasattr(other, "name")
def __eq__(self, other):
if not self._is_valid_operand(other):
return NotImplemented
# 根据name判断是否相等(都转成小写比较、忽略大小写)
return self.name.lower() == other.name.lower()
def __lt__(self, other):
if not self._is_valid_operand(other):
return NotImplemented
# 根据name判断是否相等(都转成小写比较、忽略大小写)
return self.name.lower() < other.name.lower()
# 打印被装饰之后的User类中的__gt__方法
print(User.__gt__)
singledispatch
代码如下:
from functools import *
@singledispatch
def test(arg, verbose):
if verbose:
print("默认参数为:", end=" ")
print(arg)
# 限制test函数第一个参数为int型的函数版本
@test.register(int)
def _(argu, verbose):
if verbose:
print("整型参数为:", end=" ")
print(argu)
test('Python', True) # ①
# 调用第一个参数为int型的版本
test(20, True) # ②
# 限制test函数第一个参数为list型的函数版本
@test.register(list)
def _(argb, verbose=False):
if verbose:
print("列表中所有元素为:")
for i, elem in enumerate(argb):
print(i, elem, end=" ")
test([20, 10, 16, 30, 14], True) # ③
print("\n---------------")
# 定义一个函数,不使用函数装饰器修饰
def nothing(arg, verbose=False):
print("~~None参数~~")
# 当test函数第一个参数为None类型时,转向为调用nothing函数
test.register(type(None), nothing)
test(None, True) # ④
print("\n---------------")
from decimal import Decimal
# 限制test函数第一个参数为float或Decimal型的函数版本
@test.register(float)
@test.register(Decimal)
def test_num(arg, verbose=False):
if verbose:
print("参数的一半为:", end=" ")
print(arg / 2)
# test.dispatch(类型)即可获取它转向的函数
# 当test()函数第一个参数为float时将转向到调用test_num
print(test_num is test.dispatch(float)) # True
# 当test()函数第一个参数为Decimal时将转向到调用test_num
print(test_num is test.dispatch(Decimal)) # True
# 直接调用test并不等于test_num
print(test_num is test) # False
# 获取test函数所绑定的全部类型
print(test.registry.keys())
# 获取test函数为int类型绑定的函数
print(test.registry[int])
wraps
代码如下:
from functools import wraps
def fk_decorator(f):
# 让wrapper函数看上去就像f函数
@wraps(f)
def wrapper(*args, **kwds):
print('调用被装饰函数')
return f(*args, **kwds)
return wrapper
@fk_decorator
def test():
"""test函数的说明信息"""
print('执行test函数')
test()
#print(test.__name__)
#print(test.__doc__)