一、列表知识点
1、逆序排列
lists= [1,2,3,4]
##### reverse()函数方法
lists.reverse()
print(lists)
#[4,3,2,1],不能直接print(lists.reverse),否则输出None
##### 切片方法
print(lists[::-1])
#lists[:] 表示lists[0:end],end表示lists的长度,end可以为任意长度而不会出错,lists[0:0]为[],lists[0:10]仍然为[1,2,3,4]
#lists[::],表示lists[0:end:1],同上,但1是递增值,可以改变;当为-1时,表示从0至end逆序输出。
##### reversed()函数方法
b = reversed(lists)
print(list(b))
#b为迭代器对象的内存地址,print(b)为<list_reverseiterator object at 0x000001652144E940>
#当再次输出对象b时:print(list(b)) [] 显示为空列表!,reversed()返回的是一个迭代器对象,只能进行一次循环遍历。显示一次所包含的值。
2、出栈
lists = [1,2,3,4,3]
while lists:
a = lists.pop() #列表元素出栈
print(a) #输出依次为3,4,3,2,1,先进后出
while lists:
a = lists.pop(0) #列表依次弹出index=0的元素,为列表时,pop(index)中index可正可负可为0
print(a) #输出依次为1,2,3,4,3,按照索引值弹出元素
sets = {1,2,3,4,3}
while sets:
print(sets.pop()) #集合依次弹出索引为-1的元素,逆序输出为1,2,3,4,注意集合中元素不重复,pop()中参数必须为空
3、判断输入的字符是否回文
str = input() #从键盘获取字符串,默认输入为字符串
lists = str.split(" ") #以空格为分割符,分割后为列表的存储类型
intlists = []
for num in lists:
intlists.append(int(num)) #将字符型转化为整形存进列表当中
if lists==lists[::-1]: #判断正序与逆序的元素是否相等
return True #相等则为回文字符串
4、for循环同时遍历多个列表
a = [1,2,3]
b = [2,3,4]
c = [3,4,5]
for i,j,k in zip(a,b,c):
print(i,j,k) #依次输出1,2,3 2,3,4 3,4,5
for i,j,k in zip(a[1:],b,c):
print(i,j,k) #依次输出2,2,3 3,3,4
5、将字符型列表快速转化为整形列表
a = ['1','2','3']
b = list(map(int,a)) #输出为[1,2,3]
# map() 会根据提供的函数对指定序列做映射。第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
6、列表的常用操作
'''
一、向列表中增加元素
list.append(单个元素):在list列表末端增加一个元素;
list.extend([元素1,元素2]):在list列表末端增加多个元素;
list.insert(元素序号,元素):在list列表任意位置增加一个元素
二、从列表中删除元素
list.remove(元素):从列表中删除一个元素,且并不要求此元素的位置;
del.list[元素序号]:从列表中删除指定位置的元素;
list_0 = list.pop(元素):从列表中弹出一个元素,则list列表中少一个元素;
list_0 = list.pop(元素序号):从列表中指定弹出一个元素,则list列表中少一个元素。
三、列表的其它操作
a = list.count(元素):计算它的参数在列表中出现的次数,并将次数返回;
a = list.index(元素):返回它的参数在列表中的位置,返回元素序号;#若有多个元素相同,此为只返回首端起第一个。
a = list.index(元素, 序号1,序号2):在序号1和序号2范围内,返回列表中元素位置。 #若有多个元素相同,此为只返回首端起第一个。
list.reverse() == list[::-1]:将整个列表内元素反过来排列:[1, 2, 3, 4].reverse() == [4, 3, 2, 1];
list.sort():将所有元素,从小到大排列;
'''
7、求列表当中连续且不为空的子集
# lists = [1,2,3]
def getsubset(lists):
subset = []
for i in range(0,len(subset)):
for j in range(i,len(subset)+1):
subset.append(lists[i:j])
return subset
print(getsubset(lists)) #输出[[1],[1,2],[1,2,3],[2],[2,3],[3]]
8、字符串相关操作
'''
字符串拼接
'''
s1 = "hello"
s2 = "world"
s3 = s1 + s2
#等同于 s3 = s1.join(s2)
'''
由于字符串是不可变对象,当使用“+”连接字符串的时候,每执行一次“+”操作都会申请一块新的内存,然后复制上一个“+”操作的结果和本次操作的有操作符到这块内存空间中,所以用“+”连接字符串的时候会涉及内存申请和复制;join在连接字符串的时候,首先计算需要多大的内存存放结果,然后一次性申请所需内存并将字符串复制过去。在用"+"连接字符串时,结果会生成新的对象,而用join时只是将原列表中的元素拼接起来,因此在连接字符串数组的时候会考虑优先使用join。
'''
s2 = s1.split(" ",1) #采用空格分割,只分割前4个
s1.startswith("@") #检索是否以@k开头,是则返回True
s2.endswith("d") #检索是否以的结尾,是则返回False
s2.strip("") #去掉字符串左右两侧空格和特殊字符
s1 = "asdasda"
s2 = s1.strip("adb")
print(s2) #sdas 去除分布在左右两侧的a,d,b,ad,bd
s1.lstrip("") #去除左边的特殊字符
s1.rstrip("") #去除右边的特殊字符
二、细节知识点
1、python中的“is”与“==”
a,c = 2, 2.0
b,d = 2, 2.0
print(a is b) #打印的值为true
print(a == b) #打印的值为true
print(c is d) rfswgbdgnh否指向同一个对象;== 是比较两个变量的值是否相同
判断是否为同一对象的方法为id()方法;id方法的返回值就是对象的内存地址。
a = 5555
b = 5555
print(id(a)) #打印的值为140320340495184(64位)
print(id(b)) #打印的值为140320340493392
为了提高内存利用效率,对一些数值较小的int对象,python采取重用内存的办法,所返回的内存地址相同。
2、python中的进制转化
## 十进制转化为二进制
# 一、使用内置函数来转化(bin(number))
a = 7
bin(a) #输出为ob111,注意此时省去前面的0
# 二、使用字符串格式化转化
a = "{0:0b},{1:0b}".format(7,9) # 输出为111,1001
## 此外
'''
八进制 oct() ,十六进制 hex()
'''
print(oct(a)) # 输出为0o7
print(hex(a)) # 输出为0x7
## 其他进制向十进制转换
# 一、使用int函数
int('100',a) #将100以a进制转化为10进制,a的取值范围为2~36,如果a=2,则计算为1*2^2+0*2^1+0*2^0=4,a默认值为10,即int("100")=100
# 二、使用eval函数
eval("a"), eval("0o100") #输出为7,64
3、python静态变量的计数
# 堆上的匿名参数法
def count(L=[]):
if len(L)==0:
L.append(0)
L[0] +=1
return L[0]
4、python中的输入
#输入形式为 1 2 3 4
s = input() #python中默认输入为字符串,遇到换行截止,s='1 2 3 4'
slist = s.split(' ') #将s字符串为包含字符串的列表
#将输入的列表转化为整形列表
stoint = list(map(int,input().split(' '))) #map方法
stoint = eval(input().split(' ')) #eval函数方法
#eval函数用法较好
#当输入形式为(1,2,3,4)时
s = input() #s为'(1,2,3,4)'
intval = eval(s) #intval为(1,2,3,4)
5、python当中的内置模块
一、time模块
**时间戳(timestamp) :**通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
格式化的时间字符串
元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
import time
time.sleep(5) #时间睡眠5s
t = time.time() #返回当前时间的时间戳(以秒计算,从1970年1月1日00:00:00开始到现在的时间差)
t = time.localtime() # 将一个时间戳转换为当前时区
year = t.tm_year
month = t.tm_mon
print(year) #2018
t = time.strftime("%Y-%m-%d %X",time.localtime()) #2019-09-15 15:30:59
print(time.asctime()) #Sun Sep 15 15:32:18 2019
import datetime
print(datetime.datetime.now()) #显示当前日期,精确到秒2019-09-15 15:34:41.019596
print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间加3天
print(datetime.date.fromtimestamp(time.time())) ##时间戳直接转换为日期格式2019-09-15
二、random模块
import random
print(random.random()) #0,1之间时间生成的浮点数 float
print(random.randint(1, 3)) #随机生成传入参数范围内的数字 即 1,2,3
print(random.randrange(1, 3)) #随机生成传入参数范围内的数字,range顾头不顾尾
print(random.choice([1, '23', [4, 5]])) #随机选择任意一个元素
print(random.sample([1, '23', [4, 5]], 2)) #随机选择任意两个元素
#随机生成一个验证码
#验证码
def v_code():
ret = ""
for i in range(5):
num = random.randint(0,9)
alf = chr(random.randint(65,122))
#字母与数字随机拼接
num_alf = str(random.choice([num,alf]))
ret +=num_alf
return ret
print(v_code())
三、sys模块
import sys
print(sys.argv) #命令行参数List,第一个元素是程序本身路径['D:\\Anaconda3\\lib\\site-packages\\ipykernel\\__main__.py', '-f', 'C:\\Users\\Administrator\\AppData\\Roaming\\jupyter\\runtime\\kernel-6d790dd5-9bb1-45c1-b3bd-122c5961d4ad.json']
print(sys.version) #获取Python解释程序的版本信息
print(sys.path) #返回模块的搜索路径
print(sys.maxsize) #最大的Int值
四、os模块
import os
os.getcwd() #获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") #改变当前脚本工作目录;相当于shell下cd
os.curdir #返回当前目录: ('.')
os.pardir #获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') #可生成多层递归目录
os.removedirs('dirname1') #若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') #生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') #删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() #删除一个文件
os.rename("oldname","newname") #重命名文件/目录
os.stat('path/filename') #获取文件/目录信息
os.sep #输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep #输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep #输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name #输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") #运行shell命令,直接显示
os.environ #获取系统环境变量
os.path.abspath(path) #返回path规范化的绝对路径
os.path.split(path) #将path分割成目录和文件名二元组返回
os.path.dirname(path) #返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) #返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) #如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) #如果path是绝对路径,返回True
os.path.isfile(path) #如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) #如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) #将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) #返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) #返回path所指向的文件或者目录的最后修改时间
五、json模块
过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。json 字符串必须用双引号。
import json
x="[null,true,false,1]"
#print(eval(x)) #eval函数出错
print(json.loads(x)) #[None, True, False, 1]
import json
# Writing JSON data
with open('data.json', 'w') as f:
json.dump(data, f)
# Reading data back
with open('data.json', 'r') as f:
data = json.load(f)
六、pickle模块
用pickle保存那些不重要的数据,不能成功地反序列化也没关系。
##----------------------------序列化
import pickle
dic = {"name": "rxz","age": 29,"sex":"gils"}
print(type(dic))#<class 'dict'>
j=pickle.dumps(dic)
print(type(j))#<class 'bytes'>
f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes'
f.write(j) #-------------------等价于pickle.dump(dic,f)
f.close()
#-------------------------反序列化
import pickle
f=open('序列化对象_pickle','rb')
data=pickle.loads(f.read())# 等价于data=pickle.load(f)
print(data['age'])
'''
输出为
<class 'dict'>
<class 'bytes'>
29
'''
七、shelve模块
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
import shelve #存取很方便(可以做一个简单的数据存储方案)
f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']} #存
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])
f.close()
'''
['piao', 'smoking', 'drinking']
'''
八、xml模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单。xml的格式如下,就是通过<>节点来区别数据结构的:
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:
#创建xml文档
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("xmltest.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式
##<namelist><name enrolled="yes"><age checked="no" /><sex>33</sex></name><name enrolled="no"><age>19</age></name></namelist>
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
#遍历xml文档
for child in root:
print(child.tag, child.attrib)
for i in child:
print(i.tag,i.text)
#只遍历year 节点
for node in root.iter('year'):
print(node.tag,node.text)
#---------------------------------------
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
#修改
for node in root.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated","yes")
tree.write("xmltest.xml")
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
'''
namelist
name {'enrolled': 'yes'}
age None
sex 33
name {'enrolled': 'no'}
age 19
'''
九、re模块
正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
import re
# . 就是通配符,一个点代表一个字符
s = re.findall("a...x","adsfaeyuxslg")
print(s) # ['aeyux']
# ^ 这个代表以什么开头
s = re.findall("^a..x","adsfaeyuxslg")
print(s) # ['']
# $ 以什么结尾的
a = re.findall("a..x$","adsxaeyxslgarrx")
print(a) #['arrx']
# 重复符号有4个,第四个({})代表0 到你想到取得次数
"""
{0,}=====>*
{1,}=====>+
{0,1}=====>?
{6}=====>重复6次
{1,6}=====>重复,1,2,3,4,5,6其中任何一次
"""
s = re.findall("alex{6}","asdhfalexxxxxx")
print(s) #['alexxxxxx']
s = re.findall("alex{0,6}","asdhfalexx")
print(s) #['alexx']
# 重复符号有4个,第一个(* )代表0到无穷次,贪婪匹配
# 注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
s = re.findall("d*","sfdderddddddyuyygdd")
print(s) #['', '', 'dd', '', '', 'dddddd', '', '', '', '', '', 'dd', '']
'''
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
. 匹配任意连续字符,返回值为全部的字符串
* 匹配所有字符
? 贪婪匹配
+ 表示匹配任意字符一个或多个
$ 匹配结尾字符
^ 匹配开头字符
[^abc] 匹配除了abc以外的任意字符
() 个人理解为指定()中的字符
[] 个人理解为处理特殊的字符
'''
a = "test=1234\t\t"
b = re.findall("test=.*",a) #返回值为test=1234\t\t
c = re.findall("test=(.*)\t",a) #返回值为1234\t,贪婪匹配
d = re.findall("test=(.*?)\t",a) #返回值为1234,非贪婪匹配
e = re.findall("\t$",a) #返回值为\t,匹配结尾字符
f = re.findall("[^test=]",a) #['1', '2', '3', '4', '\t', '\t']
g = re.findall("[^test].*",b) #['=1234\t\t']
a = "test(=123)\t\t"
b = re.findall("test[(](.*?)[\t]",a) #['=123)']
#除去所有的英文字符
from string import punctuation
a = "ab%$^&$sf^%%sffs^fs-./dsyf"
b = re.sub("[{}]".format(punctuation),"",a) #absfsffsfsdsyf
'''
正则随笔
'''
import re
from string import punctuation #导入所有的英文字符
from zhon.hanzi import punctuation #需要zhon包
string1 = "ab%$^&$sf^%%s\nffs^fs-./dsyf"
string2 = re.sub("[{}]".format(punctuation),"",string1)
print(string2)
string3 = re.findall("[\n](.*$)",string1)
print(string3)
string4 = re.search("[\n](.*$)",string1)
print(string4)
string5 = re.match("[\n](.*$)",string1)
print(string5)
string6 = re.search("[{}]".format(punctuation),string1)
print(string6)
string7 = re.findall("[{}]".format(punctuation),string1)
print(string7)
string8 = re.finditer("[{}]".format(punctuation),string1)
print(string8)
for m in string8:
print(m.start(),m.end())
# absfs
# ffsfsdsyf
# ['ffs^fs-./dsyf']
# <_sre.SRE_Match object; span=(13, 27), match='\nffs^fs-./dsyf'>
# None
# <_sre.SRE_Match object; span=(2, 3), match='%'>
# ['%', '$', '^', '&', '$', '^', '%', '%', '^', '-', '.', '/']
# <callable_iterator object at 0x022F3BB0>
'''
2 3
3 4
4 5
5 6
6 7
9 10
10 11
11 12
17 18
20 21
21 22
22 23
'''
十、logging模块
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
"""
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
"""
十一、其他模块
shutil模块:高级的 文件、文件夹、压缩包 处理模块(递归,文件复制等)
configparser模块:用于对特定的配置进行操作
hashlib模块:用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
6、python当中的内置函数
7、python当中的内置方法
__init__(self) | 初始化对象,在创建新对象时调用 |
---|---|
__del__(self) | 释放对象,在对象被删除之前调用 |
__new__(cls,*args,**kwd) | 实例的生成操作 |
__str__(self) | 在使用print语句时被调用 |
__getitem__(self,key) | 获取序列的索引key对应的值,等价于seq[key] |
__len__(self) | 在调用内联函数len()时被调用 |
__cmp__(stc,dst) | 比较两个对象src和dst |
__getattr__(s,name) | 获取属性的值 |
__setattr__(s,name,value) | 设置属性的值 |
__delattr__(s,name) | 删除name属性 |
__getattribute__() | getattribute()功能与__getattr__()类似 |
__gt__(self,other) | 判断self对象是否大于other对象 |
__lt__(slef,other) | 判断self对象是否小于other对象 |
__ge__(slef,other) | 判断self对象是否大于或者等于other对象 |
__le__(slef,other) | 判断self对象是否小于或者等于other对象 |
__eq__(slef,other) | 判断self对象是否等于other对象 |
__call__(self,*args) | 把实例对象作为函数调用 |
8、python当中的内置变量
vars()查看内置全局变量 | 以字典方式返回内置全局变量 |
---|---|
__doc__ | 获取文件的注释 |
__file__ | 【重点】获取当前文件的路径 |
__name__ | 【重点】获取导入文件的路径加文件名称,路径以点分割,注意:获取当前文件返回__main__,name 全局变量写在入口文件里,只有执行入口文件时的返回值才是__main__ ,如果入口文件被导入到别的文件里,此时入口文件的__name__返回值就不在是__main__,而是如果文件的路径加入口文件名称,所以我们可以用__name__全局变量来防止别人盗链入口文件 |
__builtins__ | 【重点】内置函数在这里面 |
__package__ | 获取导入文件的路径,多层目录以点分割,注意:对当前文件返回None |
__cached__ | 获取导入文件的缓存路径 |
9、Python3 迭代器与生成器
迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
print (next(it)) # 输出迭代器的下一个元素
1
print (next(it))
2
生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
#输出0 1 1 2 3 5 8 13 21 34 55
10、python中的装饰器与闭包
装饰器本质上是一个pyhton函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能。装饰器的返回值也是一个函数对象(函数的指针)。要使用类装饰器必须实现类中的__call__()方法,就相当于将实例变成了一个方法。
# 一:函数装饰函数
def wrapFun(func):
def inner(a, b):
print('function name:', func.__name__)
r = func(a, b)
return r
return inner
@wrapFun
def myadd(a, b):
return a + b+1
print(myadd(2, 3))
# function name: myadd
# 6
# 二:函数装饰类
def wrapClass(cls):
def inner(a):
print('class name:', cls.__name__)
return cls(a)
return inner
@wrapClass
class Foo():
def __init__(self, a):
self.a = a
def fun(self):
print('self.a =', self.a)
m = Foo('xiemanR')
m.fun()
# class name: Foo
# self.a = xiemanR
# 三:类装饰函数
class ShowFunName():
def __init__(self, func):
self._func = func
def __call__(self, a):
print('function name:', self._func.__name__)
return self._func(a)
@ShowFunName
def Bar(a):
return a
print(Bar('xiemanR'))
# function name: Bar
# xiemanR
# 四:类装饰类
class ShowClassName(object):
def __init__(self, cls):
self._cls = cls
def __call__(self, a):
print('class name:', self._cls.__name__)
return self._cls(a)
@ShowClassName
class Foobar(object):
def __init__(self, a):
self.value = a
def fun(self):
print(self.value)
a = Foobar('xiemanR')
a.fun()
# class name: Foobar
# xiemanR
闭包:在一个函数当中定义了一个内层函数,内层函数使用了外层函数的变量,并且外层函数的返回值为内层函数的引用。
# outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
b = 10
# inner是内函数
def inner():
#在内函数中 用到了外函数的临时变量
print(a+b)
# 外函数的返回值是内函数的引用
return inner
11、python中基本数据类型
#python3中有6个标准的数据类型
'''
1.Number(数字)
2.String(字符串)
3.List(列表)
4.Tuple(元组)
5.Set(集合)
6.Dictionary(字典)
'''
#不可变数据类型(3个):number ,string, tuple
#可变数据类型(3个):List,Dictionary(字典),Set(集合)
三、算法
1、快速排序
def quick_sort(lists):
if len(lists)<2:
return lists
else:
bench=lists[0]
more = [x for x in lists if x>bench]
equal = [x for x in lists if x==bench]
less = [x for x in lists if x<bench]
return quick_sort(more)+equal+quick_sort(less) #由大到小进行排序
四、python中链表
1、链表的创建,打印,以及元素处理
class ListNode:
def __init__(self,x):
self.val = x
self.next = None
class Solution:
def CreateListNode(self,lists): ##将列表创建为链表
node = ListNode(0)
pHead = node
for i in lists:
node.next = ListNode(i)
node = node.next
return pHead.next
def ListNodetoList(self,listnode: ListNode) -> list : ##将链表中的元素存进列表当中
lists = []
while listnode:
lists.append(listnode.val)
listnode = listnode.next
return lists
def ListNodeAddTwoNumber(self,listnode1: ListNode,listnode2: ListNode) -> ListNode: ##大数运算,将链表中的数字按进位相加得到新的链表
dumpy = ListNode(0)
pHead = dumpy
i = 0
while listnode1 or listnode2:
num = 0
if listnode1:
num +=listnode1.val
listnode1 = listnode1.next
if listnode2:
num +=listnode2.val
listnode2 = listnode2.next
num += i
if num<10:
dumpy.next = ListNode(num)
dumpy = dumpy.next
i = 0
else :
i = num//10
num = num%10
dumpy.next = ListNode(num)
dumpy = dumpy.next
if i>0:
dumpy.next = ListNode(i)
dumpy = dumpy.next
return pHead.next
五、python中二叉树
1、二叉树的创建,将列表转化为二叉树
1
/ \
2 2
/ \ / \
3 4 4 3
class TreeNode:
def __init__(self,x):
self.val = x
self.left = None
self.right = None
lists = [1,2,2,3,4,4,3] #根据上面的二叉树,遍历得到的列表
Root = TreeNode(lists[0]) #根节点
Root_1_1 = TreeNode(lists[1])
Root_1_2 = TreeNode(lists[2])
Root.left = Root_1_1
Root.right = Root_1_2
Root_1_1_1 = TreeNode(lists[3])
Root_1_1_2 = TreeNode(lists[4])
Root_1_1.left = Root_1_1_1
Root_1_1.right = Root_1_1_2
Root_1_2_1 = TreeNode(lists[5])
Root_1_2_2 = TreeNode(lists[6])
Root_1_2.left = Root_1_2_1
Root_1_2.right = Root_1_2_2
#将二叉树按照先序遍历的方式转换成列表,先序遍历方式:根左右
lists = []
def pro_order(tree):
if tree is not None:
lists.append(tree.val)
pre_order(tree.left)
pre_oder(tree.right)
return lists ## [1, 2, 3, 4, 2, 4, 3]
#将二叉树按照中序遍历的方式转换成列表,中序遍历方式:左根右
lists = []
def mid_order(tree):
if tree is not None:
mid_order(tree.left)
lists.append(tree.val)
mid_order(tree.right)
return lists ## [3, 2, 4, 1, 4, 2, 3]
#将二叉树按照后序遍历的方式转换成列表,后序遍历方式:左右根
lists = []
def post_order(tree):
if tree is not None:
post_order(tree.left)
post_order(tree.right)
lists.append(tree.val)
return lists ## [3, 4, 2, 4, 3, 2, 1]
#利用堆栈的方法实现前序遍历
def midorder(tree):
lists,st,n = [],[],tree
while n or st:
while n:
lists.append(n.val)
st.append(n)
n = n.left #左子数依次进栈
n = st.pop()
n = n.right
return lists
#利用堆栈的方法实现中序遍历
def midorder(tree):
lists,st,n = [],[],tree
while n or st: #从根节点开始,一直寻找它的左子树
while n:
st.append(n)
n = n.left #左子数依次进栈
n = st.pop()
lists.append(n.val)
n = n.right
return lists
#利用堆栈的方法实现中序遍历
#先遍历根节点,再遍历右子树,最后是左子树,这样就可以转化为和先序遍历一个类型了,最后只把遍历结果逆序输出
def mid_order(tree):
lists,st1,st2,n = [],[],[],tree
while n or st1:
while n:
st1.append(n)
st2.append(n)
n = n.right
n = st1.pop()
n = n.left
while st2:
lists.append(st2.pop().val)
return lists
'''
* 特性A,对于前序遍历,第一个肯定是根节点;
* 特性B,对于后序遍历,最后一个肯定是根节点;
* 特性C,利用前序或后序遍历,确定根节点,在中序遍历中,根节点的两边就可以分出左子树和右子树;
* 特性D,对左子树和右子树分别做前面3点的分析和拆分,相当于做递归,我们就可以重建出完整的二叉树;
* 特性E,由先序遍历遍历和中序遍历可以得到后续遍历,由中序遍历和后序遍历可以得到前序遍历,但由先序遍历和后续遍历得不到中序遍历。
'''
2、翻转二叉树
4 4
/ \ / \
2 7 7 2
/ \ / \ / \ / \
1 3 6 9 9 6 1 3
def invertTree(root:TreeNode) ->TreeNode:
if root is None:
return
else:
temp = root.left
root.left = invertTree(root.right)
root.right = invertTree(temp)
return root
3、重建二叉树
#根据二叉树的前序遍历和中序遍历得到二叉树的后序遍历
class TreeNode(object):
def __init__(self,x):
self.val=x
self.left=None
self.right=None
def RebuildBinaryTree(preorder,midorder):
if len(preorder)==0 or len(midorder)==0:
return None
root = TreeNode(preorder[0])
i = midorder.index(preorder[0]) #找到根节点元素在中序遍历当中的位置,确定左右节点的位置
root.left = RebuildBinaryTree(preorder[1:i+1],midorder[0:i]) #前序遍历0对应的首元素为根节点,故从1开始到i+1结束,共i个元素,中序遍历从0开始到i结束,也是共i个元素。
root.right = RebuildBinaryTree(preorder[i+1:],midorder[i+1:]) #前序遍历的i+1及以后是右节点,中序遍历的i为根节点,故需要从i+1到以后才是右节点
return root
def post_order(root): #递归实现后续遍历,左右根
if not root: #root为空返回0
return 0
else:
pre_order(root.left)
pre_order(root.right)
print(root.val,end=' ') #打印后续遍历的列表
preorder = [i for i in input().split()] # 输入前序遍历结果
midorder = [i for i in input().split()] # 输入中序遍历结果
post_order(RebuildBinaryTree(preorder, midorder)) # 打印后序遍历结果(最后有个空格)
'''
输入:
d g b a e c h f #前序遍历
g b d e h f c a #中序遍历
输出:
b g f h c e a d #后续遍历
'''
#根据二叉树的后续遍历与中序遍历得到前序遍历
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
def RebuildBinaryTree(postorder,midorder):
if len(postorder)==0 or len(midprder)==0:
return None
root = TreeNode(postorder[-1])
i = midorder.index(postorder[-1])
root.left = RebuildBinaryTree(postorder[0:i],midorder[0:i])
root.right = RebuildBinaryTree(postorder[i:-1],midorder[i+1:])
return root
def pre_order(root):
if not root:
return 0
else:
print(root.val,end=' ')
pre_order(root.left)
pre_order(root.right)
postorder = [i for i in input().split()]
midorder = [i for i in input().split()]
pre_order(RebuildBinaryTree(postorder, midorder))
'''
输入:
b g f h c e a d #后序遍历
g b d e h f c a #中序遍历
输出:
d g b a e c h f #前序遍历
'''
4、层次遍历二叉树
def search(root):
outlist = []
queue = [root]
while queue!=[] and root:
outlist.append(queue[0].val)
if queue[0].left!=None:
queue.append(queue[0].left)
if queue[0].right!=None:
queue.append(queue[0].right)
queue.pop(0)
return outlist
六、python中的多线程与GIL锁
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。每个线程都有它自己的一组CPU寄存器,成为线程的上下文,该上下文反映了线程上运行该线程的CPU寄存器状态。
指令指针寄存器和堆栈指针寄存器是线程上下文中最重要的两个寄存器,线程总是得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
-
线程可以被抢占。
-
在其他线程运行时,线程可以暂时搁置,这就是线程的退让。
线程可以分为:
- 内核线程:由操作系统内核创建和销毁。
- 用户线程:不需要内核支持而在用户程序中实现的线程。
Python中使用线程有两种方式:函数或者用类来包装线程对象。函数式:调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下:
import _thread
_thread.start_new_thread(function,args[,kwargs])
参数说明:
- function - 线程函数。
- args - 传递给线程函数的参数,他必须是个tuple类型。
- kwargs - 可选参数。
Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。
_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
- run(): 用以表示线程活动的方法。
- **start()😗*启动线程活动。
- join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名
通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:
#!/usr/bin/python3
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("开始线程:" + self.name)
print_time(self.name, self.counter, 5)
print ("退出线程:" + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主线程")
程序结果为:
开始线程:Thread-1
开始线程:Thread-2
Thread-1: Wed Apr 6 11:46:46 2016
Thread-1: Wed Apr 6 11:46:47 2016
Thread-2: Wed Apr 6 11:46:47 2016
Thread-1: Wed Apr 6 11:46:48 2016
Thread-1: Wed Apr 6 11:46:49 2016
Thread-2: Wed Apr 6 11:46:49 2016
Thread-1: Wed Apr 6 11:46:50 2016
退出线程:Thread-1
Thread-2: Wed Apr 6 11:46:51 2016
Thread-2: Wed Apr 6 11:46:53 2016
Thread-2: Wed Apr 6 11:46:55 2016
退出线程:Thread-2
退出主线程
线程同步
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。
#!/usr/bin/python3
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("开启线程: " + self.name)
# 获取锁,用于线程同步
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 释放锁,开启下一个线程
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
threadLock = threading.Lock()
threads = []
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t in threads:
t.join()
print ("退出主线程")
开启线程: Thread-1
开启线程: Thread-2
Thread-1: Wed Apr 6 11:52:57 2016
Thread-1: Wed Apr 6 11:52:58 2016
Thread-1: Wed Apr 6 11:52:59 2016
Thread-2: Wed Apr 6 11:53:01 2016
Thread-2: Wed Apr 6 11:53:03 2016
Thread-2: Wed Apr 6 11:53:05 2016
退出主线程
线程优先级队列( Queue)
Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。
Queue 模块中的常用方法:
- Queue.qsize() 返回队列的大小
- Queue.empty() 如果队列为空,返回True,反之False
- Queue.full() 如果队列满了,返回True,反之False
- Queue.full 与 maxsize 大小对应
- Queue.get([block[, timeout]])获取队列,timeout等待时间
- Queue.get_nowait() 相当Queue.get(False)
- Queue.put(item) 写入队列,timeout等待时间
- Queue.put_nowait(item) 相当Queue.put(item, False)
- Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
- Queue.join() 实际上意味着等到队列为空,再执行别的操作
#!/usr/bin/python3
import queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print ("开启线程:" + self.name)
process_data(self.name, self.q)
print ("退出线程:" + self.name)
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print ("%s processing %s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
# 创建新线程
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# 填充队列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# 等待队列清空
while not workQueue.empty():
pass
# 通知线程是时候退出
exitFlag = 1
# 等待所有线程完成
for t in threads:
t.join()
print ("退出主线程")
开启线程:Thread-1
开启线程:Thread-2
开启线程:Thread-3
Thread-3 processing One
Thread-1 processing Two
Thread-2 processing Three
Thread-3 processing Four
Thread-1 processing Five
退出线程:Thread-3
退出线程:Thread-2
退出线程:Thread-1
退出主线程
GIL锁
GIL是GIL是CPython中特有的全局解释器锁,C语言版本python解释器的遗留问题,使用Jypthon,Ipython等无GIL锁可避免GIL对python多线程的影响。
GIL锁使得python中同一时刻其实只有一个线程在运行,在CPython解释器中当一个线程需要执行CPU进行计算之前,它需要先获得这把大锁;否则即使已经被操作系统调度出来,但仍然无法执行计算。所以CPython解释器中,线程的想要执行CPU指令需要2个条件:
- 被操作系统调度出来【操作系统允许它占用CPU】
- 获取到GIL【CPython解释器允许它执行指令】
我们并不总是能满足这2个条件。经常出现的情况是:已经满足条件1,却被条件2限制。而这就是GIL影响Python性能的主要原因【其它语言只需满足条件1即可】。
如果python在多核CPU下执行时,其性能会变得非常差。主要原因是在单核时候,同时只有一个线程在执行CPU,所以这个线程总能获取到GIL。当转换到多核时,同时会有多个线程在不同的CPU上执行,此时不同的线程之间就需要竞争GIL,而GIL只能同时被一个线程申请到,所以会导致其它线程处于闲置状态。
在早期的Python版本(3.2之前)中,GIL除了会让多线程在多核机器下表现槽糕外,它还会导致某些线程场景占用GIL,而其它线程却无法申请到。典型场景是:
- 在2个线程的情况下
- 一个是IO密集型线程
- 一个是计算密集型线程
在Python3.4之后,由于对GIL有了较大的改进。在单核的情况下,对于单个线程长期占用GIL的情况有所好转;但是在多核的情况下,性能仍然还是没有多大的改善。但是为了能在Python中利用多核来提高计算效率,还是有如下的方法可以实现的:
- 使用python3.4或更高版本(对GIL机制进行了优化)
- 使用多进程替换多线程(多进程之间没有GIL,但是进程本身的资源消耗较多)
- 使用C编写高性能模块(with nogil调出GIL限制)
- 指定cpu运行线程(使用affinity模块)
- 使用Jython、IronPython等无GIL解释器
- 全IO密集型任务时使用多线程
- 使用协程(高效的单线程模式,也称微线程;通常与多进程配合使用)
但是多线程毕竟还是闭单线程快,这是因为在一个线程IO阻塞的时间段,其他线程可以运行
GIL 锁和互斥锁是不一样的,GIL锁是锁线程的,互斥锁是锁线程內事务的,互斥锁是开发者自己写的,GIL锁来源与C版本python解释器。
实验证明,如果放弃 GIL,使用大量细粒度的锁代替,导致单线程性能下降至少 30%。所以说 GIL 在支持多线程的同时能把单线程的优势最大地发挥出来。
根据应用场景选择最佳的性能优化方案
- I/O 密集型: 使用多线程
- I/O 密集型 & Pure Python: 使用 Pypy 解释器
- CPU 密集型: 使用多进程或把复杂逻辑用 C 扩展实现
七、装饰器
装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(也叫函数的指针)。其作用就是为已存在的函数或对象添加额外的功能。
闭包:在一个外函数中定义了一个内函数,内函数中运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
def f1(func):
def wrapper():
print("hello world!")
return func() #内函数引用外函数的变量
return wrapper
@f1
def f2():
print("Python")
def f1(data):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
func(*args, **kwargs)
print(data)
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@f1("hehe")
def f2():
print("Python1","2342")
f2()
#打印
'''
Python1 2342
hehe
Python1 2342
'''
def f1(data):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print(data)
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@f1("hehe")
def f2():
print("Python1","2342")
f2()
#打印
'''
hehe
Python1 2342
'''
def f1(data):
def wrapper(func):
def inner_wrapper(a, b):
print(data)
return func(a+a, b) #返回11,2
return inner_wrapper
return wrapper
@f1("hehe")
def f2(a,b):
print(a,b)
f2("1","2")
'''
hehe
11 2
'''
八、设计模式
一、创建者模式
1.单例模式:
该模式确保某一个类只有一个实例,某种意义来书单例的作用就是全局变量,共享状态与功能,避免对同一资源产生相互冲突的请求。用途:日志记录,打印机后台程序,数据库维护的一致性。
python中单例的实现:
1.模块导入;
2.装饰器实现;
3.__new__方法;
4.__metaclass__(元类)
class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
def test():
s1 = Singleton()
s2 = Singleton()
print(f"s1: {s1}\ns2: {s2}")
test()
'''
s1: <__main__.Singleton object at 0x028128F0>
s2: <__main__.Singleton object at 0x028128F0>
'''
#非单例模式对比
class NotSingleton:
def test2(self):
pass
def test():
s1 = NotSingleton()
s2 = NotSingleton()
print(f"s1: {s1}\ns2: {s2}")
test()
'''
s1: <__main__.Singleton object at 0x025425B0>
s2: <__main__.Singleton object at 0x02852910>
'''
2.工厂模式
工厂模式是在软件开发中用来创建对象的设计模式。其包含一个超类,超类提供一个抽象化的接口来创建一个特定的对象。基于工厂模式实现可扩展,可维护的代码。当增加一个新的类型,在不需要修改已存在的类,只增加能够产生新类型的子类。
class Person:
def __init__(self):
self.name = None
self.gender = None
def getName(self):
return self.name
def getGender(self):
return self.gender
class Male(Person):
def __init__(self, name):
print "Hello Mr." + name
class Female(Person):
def __init__(self, name):
print "Hello Miss." + name
class Factory:
def getPerson(self, name, gender):
if gender == 'M':
return Male(name)
if gender == 'F':
return Female(name)
if __name__ == '__main__':
factory = Factory()
person = factory.getPerson("Chetan", "M")
3.建造者模式
将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示。思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。
from abc import ABCMeta, abstractmethod
class Builder():
__metaclass__ = ABCMeta
@abstractmethod
def draw_left_arm(self):
pass
@abstractmethod
def draw_right_arm(self):
pass
@abstractmethod
def draw_left_foot(self):
pass
@abstractmethod
def draw_right_foot(self):
pass
@abstractmethod
def draw_head(self):
pass
@abstractmethod
def draw_body(self):
pass
class Thin(Builder):
def draw_left_arm(self):
print '画左手'
def draw_right_arm(self):
print '画右手'
def draw_left_foot(self):
print '画左脚'
def draw_right_foot(self):
print '画右脚'
def draw_head(self):
print '画头'
def draw_body(self):
print '画瘦身体'
class Fat(Builder):
def draw_left_arm(self):
print '画左手'
def draw_right_arm(self):
print '画右手'
def draw_left_foot(self):
print '画左脚'
def draw_right_foot(self):
print '画右脚'
def draw_head(self):
print '画头'
def draw_body(self):
print '画胖身体'
class Director():
def __init__(self, person):
self.person=person
def draw(self):
self.person.draw_left_arm()
self.person.draw_right_arm()
self.person.draw_left_foot()
self.person.draw_right_foot()
self.person.draw_head()
self.person.draw_body()
if __name__=='__main__':
thin=Thin()
fat=Fat()
director_thin=Director(thin)
director_thin.draw()
director_fat=Director(fat)
director_fat.draw()
4.原型模式
用原型实例创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式的本质是克隆对象,所以在对象初始化比较复杂的情况下,很实用,能大大降低耗时,提高性能。
浅拷贝:指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝的对象和源对象只是名称相同,但是他们共用一个实体。
深拷贝:对对象实例引用的字段引用的对象也进行拷贝。
import copy
from collections import OrderedDict
class Book:
def __init__(self, name, authors, price, **rest):
'''rest的例子有:出版商、长度、标签、出版日期'''
self.name = name
self.authors = authors
self.price = price # 单位为美元
self.__dict__.update(rest)
def __str__(self):
mylist = []
ordered = OrderedDict(sorted(self.__dict__.items()))
for i in ordered.keys():
mylist.append('{}: {}'.format(i, ordered[i]))
if i == 'price':
mylist.append('$')
mylist.append('\n')
return ''.join(mylist)
class Prototype:
def __init__(self):
self.objects = dict()
def register(self, identifier, obj):
self.objects[identifier] = obj
def unregister(self, identifier):
del self.objects[identifier]
def clone(self, identifier, **attr):
found = self.objects.get(identifier)
if not found:
raise ValueError('Incorrect object identifier: {}'.format(identifier))
obj = copy.deepcopy(found)
obj.__dict__.update(attr)
return obj
def main():
b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
tags=('C', 'programming', 'algorithms', 'data structures'))
prototype = Prototype()
cid = 'k&r-first'
prototype.register(cid, b1)
b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
length=274, publication_date='1988-04-01', edition=2)
for i in (b1, b2):
print(i)
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))
if __name__ == '__main__':
main()
"""
>>> python3 prototype.py
authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')
authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
edition: 2
length: 274
name: The C Programming Language (ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')
ID b1 : 140004970829304 != ID b2 : 140004970829472
"""
2、结构型模式
1.适配器模式是一种接口技术,它可以通过某个类使用另一个接口与之不兼容的类型,运用此模式,两个类的接口都无需改动。应用场景:
系统数据和行为都正确,但接口不符合时,使控制范围之外的原有接口匹配,主要应用于希望复用一些现存的类,但接口又与复用环境不一致的情况。
class Target(object):
def request(self):
print "普通请求"
class Adaptee(object):
def specific_request(self):
print "特殊请求"
class Adapter(Target):
def __init__(self):
self.adaptee = Adaptee()
def request(self):
self.adaptee.specific_request()
if __name__ == "__main__":
target = Adapter()
target.request()
'''
2.修饰器模式
修饰器模式通常用于扩展一个对象功能。
'''
import functools
def memoize(fn):
known = dict()
@functools.wraps(fn)
def memoizer(*args):
if args not in known:
known[args] = fn(*args)
return known[args]
return memoizer
@memoize
def nsum(n):
'''返回前n个数字的和'''
assert(n >= 0), 'n must be >= 0'
return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):
'''返回斐波那契数列的第n个数'''
assert(n >= 0), 'n must be >= 0'
return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':
from timeit import Timer
measure = [ {'exec':'fibonacci(100)', 'import':'fibonacci',
'func':fibonacci},{'exec':'nsum(200)', 'import':'nsum',
'func':nsum} ]
for m in measure:
t = Timer('{}'.format(m['exec']), 'from __main__ import{}'.format(m['import']))
print('name: {}, doc: {}, executing: {}, time:{}'.format(m['func'].__name__, m['func'].__doc__,m['exec'], t.timeit()))
"""
>>> python3 mymath.py
name: fibonacci, doc: Returns the nth number of the Fibonacci
sequence, executing: fibonacci(100), time: 0.4169441329995607
name: nsum, doc: Returns the sum of the first n numbers,
executing: nsum(200), time: 0.4160157349997462
"""
'''
3.外观模式
外观模式又叫门面模式,在面向对象的程序设计中,解耦是一种推崇的理念。但是事实上由于某些系统国语复杂,从而增加了客户端与子系统之间的耦合度。例如:在家观看多媒体影院时,更希望按下一个按钮就能实现影碟机,电视,音响的协同工作,而不是说每个机器都要操作一遍。这种情况下可以采用外观模式,即引入一个类对子系统进行包装,让客户端与其进行交互。
外观模式:外部与子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供了一个一直的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易。
'''
from enum import Enum
from abc import ABCMeta, abstractmethod
State = Enum('State', 'new running sleeping restart zombie')
class User:
pass
class Process:
pass
class File:
pass
class Server(metaclass=ABCMeta):
@abstractmethod
def __init__(self):
pass
def __str__(self):
return self.name
@abstractmethod
def boot(self):
pass
@abstractmethod
def kill(self, restart=True):
pass
class FileServer(Server):
def __init__(self):
'''初始化文件服务进程要求的操作'''
self.name = 'FileServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动文件服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止文件服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_file(self, user, name, permissions):
'''检查访问权限的有效性、用户权限等'''
print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))
class ProcessServer(Server):
def __init__(self):
'''初始化进程服务进程要求的操作'''
self.name = 'ProcessServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动进程服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止进程服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_process(self, user, name):
'''检查用户权限和生成PID等'''
print("trying to create the process '{}' for user '{}'".format(name, user))
class WindowServer:
pass
class NetworkServer:
pass
class OperatingSystem:
'''外观'''
def __init__(self):
self.fs = FileServer()
self.ps = ProcessServer()
def start(self):
[i.boot() for i in (self.fs, self.ps)]
def create_file(self, user, name, permissions):
return self.fs.create_file(user, name, permissions)
def create_process(self, user, name):
return self.ps.create_process(user, name)
def main():
os = OperatingSystem()
os.start()
os.create_file('foo', 'hello', '-rw-r-r')
os.create_process('bar', 'ls /tmp')
if __name__ == '__main__':
main()
"""
booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo' with permissions-rw-r-r
trying to create the process 'ls /tmp' for user 'bar'
"""
'''
4.享元模式
运用共享技术有效的支持大量细粒度的对象
内部状态:享元对象中不会随环境而改变的共享部分。比如围棋棋子的颜色。
外部状态:随环境改变而改变、不可以共享的状态就是外部状态。比如围棋棋子的位置。
应用场景:程序中使用了大量的对象,如果删除对象的外部状态,可以用相对较少的共享对象取代多组对象。
'''
import random
from enum import Enum
TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')
class Tree:
pool = dict()
def __new__(cls, tree_type):
obj = cls.pool.get(tree_type, None)
if not obj:
obj = object.__new__(cls)
cls.pool[tree_type] = obj
obj.tree_type = tree_type
return obj
def render(self, age, x, y):
print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))
def main():
rnd = random.Random()
age_min, age_max = 1, 30 # 单位为年
min_point, max_point = 0, 100
tree_counter = 0
for _ in range(10):
t1 = Tree(TreeType.apple_tree)
t1.render(rnd.randint(age_min, age_max),
rnd.randint(min_point, max_point),
rnd.randint(min_point, max_point))
tree_counter += 1
for _ in range(3):
t2 = Tree(TreeType.cherry_tree)
t2.render(rnd.randint(age_min, age_max),
rnd.randint(min_point, max_point),
rnd.randint(min_point, max_point))
tree_counter += 1
for _ in range(5):
t3 = Tree(TreeType.peach_tree)
t3.render(rnd.randint(age_min, age_max),
rnd.randint(min_point, max_point),
rnd.randint(min_point, max_point))
tree_counter += 1
print('trees rendered: {}'.format(tree_counter))
print('trees actually created: {}'.format(len(Tree.pool)))
t4 = Tree(TreeType.cherry_tree)
t5 = Tree(TreeType.cherry_tree)
t6 = Tree(TreeType.apple_tree)
print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))
main()
"""
render a tree of type TreeType.apple_tree and age 28 at (29, 80)
render a tree of type TreeType.apple_tree and age 28 at (38, 94)
render a tree of type TreeType.apple_tree and age 16 at (82, 84)
render a tree of type TreeType.apple_tree and age 18 at (43, 98)
render a tree of type TreeType.apple_tree and age 2 at (84, 72)
render a tree of type TreeType.apple_tree and age 16 at (89, 29)
render a tree of type TreeType.apple_tree and age 30 at (91, 53)
render a tree of type TreeType.apple_tree and age 12 at (92, 73)
render a tree of type TreeType.apple_tree and age 3 at (11, 54)
render a tree of type TreeType.apple_tree and age 1 at (34, 59)
render a tree of type TreeType.cherry_tree and age 11 at (67, 72)
render a tree of type TreeType.cherry_tree and age 27 at (65, 81)
render a tree of type TreeType.cherry_tree and age 27 at (10, 48)
render a tree of type TreeType.peach_tree and age 11 at (35, 38)
render a tree of type TreeType.peach_tree and age 3 at (58, 83)
render a tree of type TreeType.peach_tree and age 18 at (73, 50)
render a tree of type TreeType.peach_tree and age 24 at (94, 3)
render a tree of type TreeType.peach_tree and age 4 at (2, 9)
trees rendered: 18
trees actually created: 3
4866032 == 4866032? True
4866032 == 4742704? False
"""
九、获取目录下所有图片
import os
trainpath='C:\\Users\\Administrator\\Desktop\\reduction'
def get_img_file(file_name):
imagelist = []
for parent, dirnames, filenames in os.walk(file_name):
for filename in filenames:
if filename.lower().endswith(('.bmp', '.dib', '.png', '.jpg', '.jpeg', '.pbm', '.pgm', '.ppm', '.tif', '.tiff')):
imagelist.append(os.path.join(parent, filename))
return imagelist
print(get_img_file(trainpath))
十、numpy相关操作
操作 | 解释 | 结果 |
---|---|---|
np.random.permutation(10) | 产生10个不重复的随机数 | [5 4 0 6 3 2 9 8 1 7] |
np.array([i for i in range(10)]) | [0 1 2 3 4 5 6 7 8 9] | |