python基础python中的可变不可变类型数据类型列表元祖列表和元组经常使用函数字符串字典将两个列表组合成字典集合字符编码python2和python3的区别python2和python3中编码转换深拷贝、浅拷贝三元运算IO多路复用select、poll 、epoll(同步io)进程(资源分配的单位)、线程(操做系统调度的最小单位)、协程进程: 一个在运行起来的程序 系统给他分配资源 (运行在内存) 提资源进程说明进程池线程: 操做系统最小的调度单位,状态保存在cpu的栈中经常使用方法join()方法isAlive()方法getName()方法setDaemon()方法线程锁线程特性线程池协程: 微线程,纤程。 相似于单线程,不一样于单线程,由于它能够实现并发效果,由于有gevent(封装了c语言的greenlet) 遇io自动切换(greenlet能够检测io),把这个io请求交给epoll猴子补丁协程优势:缺点:高阶函数1.map2.reduce3.filter4.sorted5.lambda(匿名函数)GIL全局解释器锁一、什么是GIL二、GIL的做用三、GIL的影响四、如何避免GIL的影响5 为何有时候加了GIL全局解释器锁 ,还要在加线程锁?线程锁装饰器、迭代器、生成器迭代器 含有iter和next方法 (包含next方法的可迭代对象就是迭代器)迭代器的定义:可迭代对象迭代器和可迭代对象关系:迭代器仅是一容器对象,它实现了迭代器协议。它有两个基本方法iter方法会返回一个迭代器(iterator),所谓的迭代器就是具备next方法的对象。在调用next方法时,迭代器会返回它的下一个值,若是next方法被调用,但迭代器中没有值能够返就会引起一个StopIteration异常生成器yield运行机制手写斐波那契迭代器生成器区别装饰器装饰器必须准寻得原则:手写三级装饰器装饰器的应用场景闭包闭包特色os和sys模块的做用?面向对象面向对象方法静态方法类方法属性方法特殊(魔术)方法单例模式面向对象属性公有属性普通属性私有属性反射新式类和经典类的区别面向对象深度优先和广度优先是什么?三大特性:封装,继承,多态Encapsulation 封装(隐藏实现细节)Inheritance 继承(代码重用)Polymorphism 多态(接口重用)垃圾回收机制1.引用计数原理优势缺点2.标记-清除原理3.分代回收三种读文件方式1.readline()2.readlines()3.read(size)tcp udptcp三次握手四次挥手TCP与UDP比较Websocket数据结构栈栈的定义栈的特色栈的基本操做栈的应用场景队列队列的定义队列的使用方法链表单链表链表反转双链表单向循环链表数组python中list与数组比较字典实现原理哈希表Python经常使用模块subprocesssubprocess原理subprocess.Popen()subprocess.PIPE paramikoParamiko模块做用re经常使用正则表达式符号匹配时忽略大小写syssys基本方法ostimetime()模块中的重要函数**time()模块时间转换**datetimehtml
可变数据类型:列表、字典python
不可变数据类型:数字、字符串、元组linux
append 用于在列表末尾追加新的对象ios
count 方法统计某个元素在列表中出现的次数正则表达式
a = ['aa','bb','cc','aa','aa']
print(a.count('aa')) #the result : 3
extend方法能够在列表的末尾一次性追加另外一个序列中的多个值shell
a = [1,2,3]
b = [4,5,6]
a.extend(b) #the result :[1, 2, 3, 4, 5, 6]
index 函数用于从列表中找出某个值第一个匹配项的索引位置编程
insert 方法用于将对象插入到列表中 结合下标使用windows
pop 方法会移除列表中的一个元素(默认是最后一个),而且返回该元素的值数组
remove 方法用于移除列表中某个值的第一个匹配项浏览器
a = ['aa','bb','cc','aa']
a.remove('aa') #the result : ['bb', 'cc', 'aa']
reverse 方法将列表中的元素反向存放
sort 方法用于对列表进行排序
enumrate 和for循环差很少 只是能获取下标的同时还能获取item
li = [11,22,33]
for k,v in enumerate(li, 1):
print(k,v)
#打印结果以下:
1 11
2 22
3 33
元祖和列表同样、只不过元祖是只读列表
com(x,y) 比较两个值
len(seq) 返回序列的长度
list(seq) 把序列转换成列表
max(args) 返回序列或者参数集合中得最大值
min(args) 返回序列或者参数集合中的最小值
reversed(seq) 对序列进行反向迭代
sorted(seq) 返回已经排列的包含seq 全部元素的列表
tuple(seq) 把序列转换成元组
使用百分号(%)字符串格式化
使用format字符串格式化
find方法能够在一个较长的字符串中查找子串,他返回子串所在位置的最左端索引,若是没有找到则返回-1
a = 'abcdefghijk'
print(a.find('abc')) #the result : 0
print(a.find('abc',10,100)) #the result : 11 指定查找的起始和结束查找位置
join方法 是很是重要的字符串方法,链接序列中的元素,而且须要被链接的元素都必须是字符串。
a = ['1','2','3']
print('+'.join(a)) # 1+2+3
split方法 是很是重要的字符串,用来将字符串分割成序列
print('1+2+3+4'.split('+')) # ['1', '2', '3', '4']
strip 方法返回去除首位空格(不包括内部)的字符串
print(" test test ".strip()) #“test test”
replace方法 返回某字符串全部匹配项均被替换以后获得字符串
print("This is a test".replace('is','is_test')) # This_test is_test a test
clear方法清除字典中全部的项,这是一个原地操做,因此无返回值(或则说返回None)
d = {}
d['Tom']=8777
d['Jack']=9999
print(d) # {'Jack': 9999, 'Tom': 8777}
d.clear()
print(d) # {}
copy方法返回一个具备相同 ”键-值” 对的新字典,而不是副本
d = {'Tom':8777,'Fly':6666}
a = d.copy()
a['Tom'] = '改变后的值'
print(d) #{'Fly': 6666, 'Tom': 8777}
print(a) #{'Fly': 6666, 'Tom': '改变后的值'}
# 查看内存地址
d={'tom':122,'fly':221}
id(d)
1932459885696
a=d.copy()
a
{'tom': 122, 'fly': 221}
id(a)
1932488640048
fromkeys方法使用给定的键创建新的字典,每一个键都对应一个默认的值None。
get方法是一个访问字典项的方法
for循环字典的三种方法
d = {'Tom':8777,'Jack':8888,'Fly':6666}
for k,v in d.items():
print(k,v)
for k in d.values():
print(k)
for k in d.keys():
print(k)
d = {'Tom':8777,'Jack':8888,'Fly':6666}
for k,v in d.items():
print(k,v)
for k in d.values():
print(k)
for k in d.keys():
print(k)
pop方法 用于得到对应与给定键的值,而后将这个”键-值”对从字典中移除
update方法能够利用一个字典项更新另外一个字典,提供的字典中的项会被添加到旧的字典中
>>> a
{'tom': 122, 'fly': 221}
>>> b={'age':20}
>>> a.update(b)
>>> a
{'tom': 122, 'fly': 221, 'age': 20}
keys = ['a', 'b']
values = [1, 2]
#一、zip生成字典
print(dict(zip(keys,values))) # {'a': 1, 'b': 2}
#二、for循环推倒字典
print({keys[i]: values[i] for i in range(len(keys))}) # {'a': 1, 'b': 2}
list_1 = [1,2,3,4,5,1,2]
#一、去重(去除list_1中重复元素1,2)
list_1 = set(list_1) #去重: {1, 2, 3, 4, 5}
print(list_1)
list_2 = set([4,5,6,7,8])
#二、交集(在list_1和list_2中都有的元素4,5)
print(list_1.intersection(list_2)) #交集: {4, 5}
#三、并集(在list_1和list_2中的元素所有打印出来,重复元素仅打印一次)
print(list_1.union(list_2)) #并集: {1, 2, 3, 4, 5, 6, 7, 8}
#四、差集
print(list_1.difference(list_2)) #差集:在list_1中有在list_2中没有: {1, 2, 3}
print(list_2.difference(list_1)) #差集:在list_1中有在list_2中没有: {8, 6, 7}
#五、子集
print(list_1.issubset(list_2)) #子集: False List_1中的元素是否所有在list2中
#六、父集
print(list_1.issuperset(list_2)) #父集: False List_1中是否包含list_2中的全部元素
#七、交集
print(list_1 & list_2) #交集 {4, 5}
#八、union并集
print(list_1 | list_2) #并集: {1, 2, 3, 4, 5, 6, 7, 8}
#九、difference差集
print(list_1 - list_2) #差集: {1, 2, 3}
#十、在集合中添加一个元素999
list_1.add(999)
print(list_1) #Add()方法: {1, 2, 3, 4, 5, 999}
#十一、删除集合中任意一个元素不会打印删除的值
list_1.pop() #Pop()方法: 无返回值
#十二、discard删除集合中的指定元素,如过没有则返回None
print(list_1.discard("ddd")) #Discard()方法: 删除指定的值,没有返回None
ASCII
ASCII不支持中文字符
GBK
是中国的中文字符(中国人本身研发的),其包含了简体中文和繁体中文的字符
Unicode : 万国编码(Unicode 包含GBK)
Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每一个字符设定了统一而且惟一的二进制编码
规定虽有的字符和符号最少由 16 位来表示(2个字节),即:2 **16 = 65536
这里还有个问题:使用的字节增长了,那么形成的直接影响就是使用的空间就直接翻倍了
Utf-8 : 可变长码, 是Unicode 的扩展集
UTF-8编码:是对Unicode编码的压缩和优化,他再也不使用最少使用2个字节,而是将全部的字符和符号进行分类
ASCII码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存
从编码的角度来讲
python2 默认编码方式ASCII码(不能识别中文,要在文件头部加上 #-- encoding:utf-8 -- 指定编码方式)
python3 默认编码方式UTF-8(能识别中文,是Unicode 的扩展集)
(可识别中文)
从输出(print)的角度来讲
python2中加不加括号均可以打印
python3中必须加括号
从输入(input)的角度来讲
python2 raw_input()
python3 input()
从range()函数的角度来讲
python2 range()/xrange()
python3 range()
从类的角度来讲
python3 中都是新式类python2 中经典类和新式类混合
新式类中使用广度优先,经典类中使用深度优先
python3 可使用superpython2 不能使用super
从字符串的角度来讲
python2中字符串有str和unicode两种类型
python3 中字符串有str和字节(bytes) 两种类型
从语法格式角度来讲
python3中再也不支持u中文的语法格式
python2中支持
在python3中字符串默认是unicode因此不须要decode(),直接encode(编码)成想要转换的编码如gb2312
在python2中默认是ASCII编码,必须先转换成Unicode,Unicode 能够做为各类编码的转换的中转站
深拷贝就是将一个对象拷贝到另外一个对象中,这意味着若是你对一个对象的拷贝作出改变时,不会影响原对象。在Python中,咱们使用函数deepcopy()执行深拷贝
而浅拷贝则是将一个对象的引用拷贝到另外一个对象上,因此若是咱们在拷贝中改动,会影响到原对象。咱们使用函数copy()执行浅拷贝
浅拷贝只是增长了一个指针指向一个存在的地址,
而深拷贝是增长一个指针而且开辟了新的内存,这个增长的指针指向这个新的内存。
三元运算格式: result=值1 if x<y else 值2 if条件成立result=1,不然result=2
做用:三元运算,又称三目运算,主要做用是减小代码量,是对简单的条件语句的缩写
#一个简单的三元运算
a=name='小草' if1=1 else '小花'
print(a) # 小草
#三元运算 + lambda
f = lambda x:x if x % 2 != 0 else x + 100
print(f(10)) # 110
不管是sellect、poll、epoll他们三个都是在I/O多路复用中检测多个socket连接,与数据从内核态到数据态没有什么关系
https://www.cnblogs.com/xiaonq/p/7907871.html#i3
select,poll,epoll都是IO多路复用中的模型
内核空间 操做系统才能访问 操做系统 能够调用cpu 挂起进程
用户空间 如qq 微信 运行在用户空间
IO多路复用(重点)
特色: 用户仍是要等待数据从内核拷贝到用户进程
Windows下只支持select
Epoll有回调 会把数据加到链表中
Select 无论你有没数据 都放到链表中
协程利用epoll greelit监听请求
协程又称微线程,协程最主要的做用是在相似单线程的条件下实现并发的效果,但实际上仍是串行的(像yield同样),为何能处理并发,由于遇IO自动切换,协程内封装Greenlet(遇到IO手动切换) 和Gevent(遇到IO自动切换),若是是耗时任务就会IO切换任务,会把任务交给操做系统,而后利用epoll,epoll有回调 会把数据加到链表中,告诉协程结果
协程通常用于网络请求 socket 连接
请求自己是从内核copy到用户空间
select (能监控数量有限(最大1024),不告诉用户程序具体哪一个链接有数据)
poll(和select同样,仅仅去除了最大监控数量,算是epoll过分)
epoll (不只没有最大监控数量限制,还能告诉用户程序哪一个链接有活跃(数据))一般使用epoll
epoll() 中内核则维护一个链表,epoll_wait 直接检查链表是否是空就知道是否有文件描述符准备好了
在内核实现中 epoll 是根据每一个 sockfd 上面的与设备驱动程序创建起来的回调函数实现的。
在高并发状况下, 链接活跃度不是很高, epoll比select好
在并发不高状况下, 链接活跃度高, select比epoll好
线程是指进程内的一个执行单元,
# 进程
进程拥有本身独立的堆和栈,既不共享堆,亦不共享栈,进程由操做系统调度。
# 线程
线程拥有本身独立的栈和共享的堆,共享堆,不共享栈,线程亦由操做系统调度
# 协程和线程
协程避免了无心义的调度,由此能够提升性能;但同时协程也失去了线程使用多CPU的能力
进程与线程的区别
(1)地址空间:线程是进程内的一个执行单位,进程内至少有一个线程,他们共享进程的地址空间,而进程有本身独立的地址空间
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是
(4)两者都可并发执行
(5)每一个独立的线程有一个程序运行的入口
协程与线程
(1)一个线程能够有多个协程,一个进程也能够单独拥有多个协程,这样Python中则能使用多核CPU
(2)线程进程都是同步机制,而协程是异步
(3)协程能保留上一次调用时的状态
通讯的三种方式
1 进程队列queue
2 管道pipe
3 共享数据manage
多个进程能够在不一样的 CPU 上运行,互不干扰
同一个CPU上,能够运行多个进程,由操做系统来自动分配时间片
开多进程是为了并发,一般有几个cpu核心就开几个进程,可是进程开多了会影响效率,主要体如今切换的开销,因此引入进程池限制进程的数量。
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,若是进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
实现全部线程都执行结束后再执行主线程
若是一个线程或者在函数执行的过程当中调用另外一个线程,而且但愿待其完成操做后才能执行, 那么在 调用线程的时就可使用被调线程的join方法join([timeout]) timeout:可选参数,线程运行的最长时间
查看线程是否还在运行
得到线程名
主线程退出时,须要子线程随主线程退出,则设置子线程的setDaemon()
线程锁也叫用户锁 也叫互斥锁、当前线程还未操做完成前其余全部线程都没法对其操做,即便已经释放了GIL锁
线程,必须在一个存在的进程中启动运行
线程使用进程得到的系统资源,不会像进程那样须要申请CPU等资源
线程没法给予公平执行时间,它能够被其余线程抢占,而进程按照操做系统的设定分配执行时间
系统启动一个新线程的成本是比较高的,由于它涉及与操做系统的交互。在这种情形下,使用线程池能够很好地提高性能,尤为是当程序中须要建立大量生存期很短暂的线程时,更应该考虑使用线程池。
线程池在系统启动时即建立大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它。当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数。
greenlet框架封装了yield语句、挂起函数,直到稍后使用next()或send()操做进行恢复为止
用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();
做用是把标准库中的thread/socket等给替换掉.无需修改任何代码,把它变成了非阻塞
1.无需线程上下文切换的开销 2.无需原子操做锁定及同步的开销 3.方便切换控制流,简化编程模型 4.高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。因此很适合用于高并发处理。
1.没法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程须要和进程配合才能 运行在多CPU上.固然咱们平常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应
2.线程阻塞(Blocking)操做(如IO时)会阻塞掉整个程序
并行 :是多个程序运行在多个cpu上
并发 :是一个时间段内,有几个程序在同一个cpu上运行,可是任意时刻只有一个程序在cpu上运行
通常多线程能够称为并发 ,由于一个进程能够有多个线程,强调的是一个进程
详细介绍 https://v3u.cn/book/p4.html 1.5
通常状况map()函数接收两个参数,一个函数(该函数接收一个参数),一个序列,将传入的函数依次做用到序列的每一个元素,并返回一个新的Iterator(迭代器)。 例若有这样一个list:['pYthon', 'jaVa', 'kOtlin'],如今要把list中每一个元素首字母改成大写,其它的改成小写,能够这样操做:
>>> def f(s):
... return s.title()
...
>>> l = map(f, ['pYthon', 'jaVa', 'kOtlin'])
>>> list(l)
['Python', 'Java', 'Kotlin']
和map()用法相似,reduce把传入的函数做用在一个序列上,但传入的函数须要接收两个参数,传入函数的计算结果继续和序列的下一个元素作累积计算。
例若有一个list,里边的元素都是字符串,要把它拼接成一个字符串:
>>> from functools import reduce
>>> def f(x, y):
... return x + y
...
>>> reduce(f, ['ab', 'c', 'de', 'f'])
'abcdef'
filter()一样接收一个函数和一个序列,而后把传入的函数依次做用于序列的每一个元素,若是传入的函数返回true则保留元素,不然丢弃,最终返回一个Iterator。
例如一个list中元素有纯字母、纯数字、字母数字组合的,咱们要保留纯字母的:
>>> def f(s):
... return s.isalpha()
...
>>> l = filter(f, ['abc', 'xyz', '123kg', '666'])
>>> list(l)
['abc', 'xyz']
sorted()函数就是用来排序的,同时能够本身定义排序的规则。
>>> sorted([6, -2, 4, -1])
[-2, -1, 4, 6]
>>> sorted([6, -2, 4, -1], key=abs)
[-1, -2, 4, 6]
>>> sorted([6, -2, 4, -1], key=abs, reverse=True)
[6, 4, -2, -1]
>>> sorted(['Windows', 'iOS', 'Android'])
['Android', 'Windows', 'iOS']
>>> d = [('Tom', 170), ('Jim', 175), ('Andy', 168), ('Bob', 185)]
>>> def by_height(t):
... return t[1]
...
>>> sorted(d, key=by_height)
[('Andy', 168), ('Tom', 170), ('Jim', 175), ('Bob', 185)]
lambda只是一个表达式,函数体比def简单不少。
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
lambda表达式是起到一个函数速写的做用。容许在代码内嵌入一个函数的定义。
格式:lambda的通常形式是关键字lambda后面跟一个或多个参数,紧跟一个冒号,以后是一个表达式。
m=lambda i:i
lista=sorted([1,-2,3,-4,5,-6],key=abs)
print(lista) #结果: [1, -2, 3, -4, 5, -6]
# 利用 filter、lambda表达式 获取列表中元素小于33的全部元素
l1= [11,22,33,44,55]
a = filter(lambda x: x<33, l1)
print(list(a))
GIL全称Global Interpreter Lock,即全局解释器锁。 做用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行。
GIL并非Python的特性,Python彻底能够不依赖于GIL。
为了更有效的利用多核处理器的性能,就出现了多线程的编程方式 ,同一个进程里线程资源是共享的,当各个线程访问数据资源时会出现竞状态 ,会出现数据混乱,解决多线程之间数据完整性和状态同步最简单的方式就是加锁。GIL能限制多线程同时执行,保证同一时间内只有一个线程在执行。
GIL无疑就是一把全局排他锁。毫无疑问全局锁的存在会对多线程的效率有不小影响。甚至就几乎等于Python是个单线程的程序。
方法一:用进程+协程 代替 多线程的方式 在多进程中,因为每一个进程都是独立的存在,因此每一个进程内的线程都拥有独立的GIL锁,互不影响。可是,因为进程之间是独立的存在,因此进程间通讯就须要经过队列的方式来实现。
方法二 : 更换解释器
像JPython和IronPython这样的解析器因为实现语言的特性,他们不须要GIL的帮助。然而因为用了Java/C#用于解析器实现,他们也失去了利用社区众多C语言模块有用特性的机会。因此这些解析器也所以一直都比较小众。
由于cpu是分时分片的 ,若是GIL处理的任务特别繁琐,到必定时间会自动切换其余线程 形成混乱 ,因此要加一个线程锁。
GIL(全局解释器锁)
GIL并非Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不一样线程对共享资源访问的互斥,才引入了GIL
在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,没法利用多核优点
互斥锁(同步锁)
互斥锁是用来解决上述的io密集型场景产生的计算错误,即目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据。
保护不一样的数据就应该加不一样的锁。因此当有多个互斥锁存在的时候,可能会致使死锁(有多是一个线程拿到锁,并无释放)
递归锁(重要)
解决死锁
Semaphore(信号量)
实际上也是一种锁,该锁用于限制线程的并发量
迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到全部的元素都被访问一遍后结束。 迭代器只能往前不会后退 。
可被for
循环遍历的对象都是可迭代的(Iterable)类型;
一个实现了iter方法的对象是可迭代的,一个实现next方法的对象是迭代器
㈠ next方法
返回容器的下一个元素
㈡ iter方法
返回迭代器自身
包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器
生成器工做原理
生成器是这样一个函数,它记住上一次返回时在函数体中的位置。
对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的全部局部变量都保持不变。
在Python中,yield就是一个生成器。 若是在函数内使用了yield关键字时,这个函数就是一个生成器
当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把yield 的参数给你,以后生成器就不会往下继续运行。
当你问他要下一个数时,他会从上次的状态开始运行,直至出现yield语句,把参数给你,以后停下。如此反复
每当调用一次迭代器的next函数,生成器函数运行到yield之处,返回yield后面的值且在这个地方暂停,全部的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出
def fbnq(n):
a,b=0,1
while n>a:
yield a
a,b=b,a+b
if __name__ == '__main__':
f=fbnq(9)
print(next(f)) #打印结果 0
print(next(f)) #打印结果 1
每次‘yield’暂停循环时,生成器会保存本地变量的状态。而迭代器并不会使用局部变量,它只须要一个可迭代对象进行迭代。 使用类能够实现你本身的迭代器,但没法实现生成器。 生成器运行速度快,语法简洁,更简单。 迭代器更能节约内存。
装饰器做用:本质是函数(装饰其余函数)就是为其余函数添加其余功能
不能修改被装饰函数的源代码
不能修改被装饰函数的调用方式
import time
user,passwd = 'aaa','123'
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap")
def bbs():
print("welcome to bbs page")
index()
print(home()) #wrapper()
bbs()
1,引入日志2,函数执行时间统计3,执行函数前预备处理4,执行函数后清理功能5,权限校验等场景6,缓存7,事务处理
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,而且外函数的返回值是内函数的引用,这样就构成了一个闭包
可是闭包是一种特殊状况,若是外函数在结束的时候发现有本身的临时变量未来会在内部函数中用到,就把这个临时变量绑定给了内部函数,而后本身再结束。
必须有一个内嵌函数
内嵌函数必须引用外部函数中的变量
外部函数的返回值必须是内嵌函数
OS模块是Python标准库中的一个用于访问操做系统功能的模块,使用OS模块中提供的接口,能够实现跨平台访问sys模块主要是用于提供对python解释器相关的操做
做用:静态方法能够更好的组织代码,防止代码变大后变得比较混乱。
特性: 静态方法只是名义上归类管理,实际上在静态方法里访问不了类或则实例中的任何属性
静态方法使用场景: 常常有一些跟类有关系的功能但在运行时又不须要实例和类参与的状况下 须要用到静态方法. 好比更改环境变量或者修改其余类的属性等能用到静态方法. 这种状况能够直接用函数解决, 但这样一样会扩散类内部的代码,形成维护困难.
调用方式: 既能够被类直接调用,也能够经过实例调用
class Dog(object):
def __init__(self,name):
self.name = name
@staticmethod
def eat():
print("I am a static method")
d = Dog("ChenRonghua")
d.eat() #方法1:使用实例调用
Dog.eat() #方法2:使用类直接调用
做用:无需实例化直接被类调用
特性: 类方法只能访问类变量,不能访问实例变量
类方法使用场景: 当咱们还未建立实例,可是须要调用类中的方法
调用方式: 既能够被类直接调用,也能够经过实例调用
class Dog(object):
name = '类变量' #在这里若是不定义类变量仅定义实例变量依然报错
def __init__(self,name):
self.name = '实例变量'
self.name = name
@classmethod
def eat(self,food):
print("%s is eating %s"%(self.name,food))
Dog.eat('baozi') #方法1:使用类直接调用
d = Dog("ChenRonghua")
d.eat("包子") #方法2:使用实例d调用
做用:属性方法把一个方法变成一个属性,隐藏了实现细节,调用时没必要加括号直接d.eat便可调用self.eat()方法
class Dog(object):
def __init__(self, name):
self.name = name
@property
def eat(self):
print(" %s is eating" % self.name)
d = Dog("ChenRonghua")
d.eat()
# 调用会出如下错误, 说NoneType is not callable, 由于eat此时已经变成一个静态属性了,
# 不是方法了, 想调用已经不须要加()号了,直接d.eat就能够了
__ doc __ 表示类的描述信息
__ call __ 对象后面加括号,触发执行
__ str __ 若是一个类中定义了__ str __方法,在打印对象时,默认输出该方法的返回值
__ dict __ 查看类或对象中的全部成员
new和init的区别
一、 new是一个静态方法,而init是一个实例方法. 二、 new方法会返回一个建立的实例,而init什么都不返回. 三、 只有在new返回一个cls的实例时后面的init才能被调用. 四、 当建立一个新实例时调用new,初始化一个实例时用init.
一、单例模式:永远用一个对象得实例,避免新建太多实例浪费资源二、实质:使用new方法新建类对象时先判断是否已经创建过,若是建过就使用已有的对象三、使用场景:若是每一个对象内部封装的值都相同就能够用单例模式
class Foo(object):
instance = None
def __init__(self):
self.name = 'alex'
def __new__(cls, *args, **kwargs):
if Foo.instance:
return Foo.instance
else:
Foo.instance = object.__new__(cls,*args,**kwargs)
return Foo.instance
obj1 = Foo() # obj1和obj2获取的就是__new__方法返回的内容
obj2 = Foo()
print(obj1,obj2)
# 运行结果: <__main__.Foo object at 0x00D3B450> <__main__.Foo object at 0x00D3B450>
# 运行结果说明:
# 这能够看到咱们新建的两个Foo()对象内存地址相同,说明使用的•同一个类,没有重复创建类
class Role(object): #一、在定义类时继承object就是新式类,没有就是就是旧类式 public_object = "public" #二、在类例定义一个公有属性:全部实例都能访问的属性叫“公有属性” def __init__(self,name,role,weapon,life_value=100,money=15000): #构造函数==初始化方法:模板 self.name = name #三、普通属性 self.__heart= "Normal" #四、私有属性在外面没法访问,在名字前加__(双下划线) 外部没法访问 def shot(self): #五、类的方法 print("%s is shooting..."%self.name)
公有属性:在内存中仅存一份
普通属性:每一个实例对象在内存存一份
私有属性:实例在外部没法调用
反射的核心本质就是以字符串的形式去导入个模块,利用字符串的形式去执行函数。
Django中的 CBV就是基于反射实现的。
❶经典类 没有继承object , 新式类 继承了object
❷多继承中,新式类采用广度优先搜索,而旧式类是采用深度优先搜索,python3中全是广度查询
❸在继承中新式类和经典类写法区别
SchoolMember.__init__(self,name,age,sex) #经典类写法 super(Teacher,self).__init__(name,age,sex) #新式类写法
一、区别
1) 二叉树的深度优先遍历的非递归的通用作法是采用栈,广度优先遍历的非递归的通用作法是采用队列。
2) 深度优先遍历:对每个可能的分支路径深刻到不能再深刻为止,并且每一个结点只能访问一次。要特别注意的是,二叉树的深度优先遍历比较特殊,能够细分为先序遍历、中序遍历、后序遍历。具体说明以下:
广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也能够从右往左)访问结点,访问完一层就进入下一层,直到没有结点能够访问为止。
在面向对象思想中,对一个类,将数据和过程封包围起来,对外隐藏具体的实现细节 而且数据(成员变量和成员函数)在内部是彻底自由使用的,而外部对数据的访问是加访问限定的,某些对操做只能根据由内部提供接口。
继承能够说是一种代码复用的手段,咱们在一个现有类上想扩展出一些东西的时候,不须要再次重复编写上面的代码,而是采用一种继承的思想。在派生出的子类里添加一些咱们想要的数据或方法,也能够理解为从通常到特殊的过程。
这里先说运行时多态,实际上是指在继承体系中父类的一个接口(必须为虚函数),在子类中有多种不一样的实现,父对象就能够根据当前赋值给它的子对象的特性以不一样的方式运做。即经过父类指针或者引用能够访问到子类的接口(虚函数),看上去就像是一个相同的动做,会出现多种不一样的结果。
当一个对象的引用被建立或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1
当对象的引用计数减小为0时,就意味着对象已经再没有被使用了,能够将其内存释放掉。
引用计数有一个很大的优势,即实时性,任何内存,一旦没有指向它的引用,就会被当即回收,而其余的垃圾收集技术必须在某种特殊条件下才能进行无效内存的回收。
引用计数机制所带来的维护引用计数的额外操做与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的,
这显然比其它那些垃圾收集技术所带来的额外操做只是与待回收的内存数量有关的效率要低。
同时,由于对象之间相互引用,每一个对象的引用都不会为0,因此这些对象所占用的内存始终都不会被释放掉。
为了解决以上问题:
标记-清除: 只关注那些可能会产生循环引用的对象,
把全部能够访问到的对象打上标记,而后清扫一遍内存空间,把全部没标记的对象释放
缺点:标记和清除的过程效率不高
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点
以引用为边构成的图,把全部能够访问到的对象打上标记,而后清扫一遍内存空间,把全部没标记的对象释放
将系统中的全部内存块根据其存活时间划分为不一样的集合,每个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减少。
也就是说,活得越长的对象,就越不多是垃圾,就应该减小对它的垃圾收集频率。
那么如何来衡量这个存活时间:一般是利用几回垃圾收集动做来衡量,若是一个对象通过的垃圾收集次数越多,能够得出:该对象存活时间就越长。
readline()每次读取一行,当前位置移到下一行readline()做用:readline 的用法,速度是fileinput的3倍左右,每秒3-4万行,好处是 一行行读 ,不占内存,适合处理比较大的文件,好比超过内存大小的文件
#readline读取大文件# f1 = open('test02.py','r') f2 = open('test.txt','w') while True: line = f1.readline() if not line: break f2.write(line) f1.close() f2.close()
readlines()读取整个文件全部行,保存在一个列表(list)变量中,每行做为一个元素readlines()做用:readlines会把文件都读入内存,速度大大增长,可是没有这么大内存,那就只能乖乖的用readline
#readlines读文件# f1=open("readline.txt","r") for line in f1.readlines(): print(line)
read(size)从文件当前位置起读取size个字节,若是不加size会默认一次性读取整个文件(适用于读取小文件)read(n)读取指定长度的文件
f = open(r"somefile.txt") print(f.read(7)) # Welcome 先读出 7 个字符 print(f.read(4)) #‘ to ‘ 接着上次读出 4 个字符 f.close() seek(offset[, whence]) 随机访问 :从文件指定位置读取或写入 f = open(r"somefile.txt", "w") f.write("01234567890123456789") f.seek(5) f.write("Hello, World!") f.close() f = open(r"somefile.txt") print(f.read()) # 01234Hello, World!89 tell 返回当前读取到文件的位置下标
####一、第一次握手 # 创建链接时,客户端发送SYN包到服务器,其中包含客户端的初始序号seq=x,并进入SYN_SENT状态,等待服务器确认。 ####二、第二次握手 # 服务器收到请求后,必须确认客户的数据包。同时本身也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN_RECV状态。 ####三、第三次握手 # 客户端收到服务器的SYN+ACK包,向服务器发送一个序列号(seq=x+1),确认号为ack(客户端)=y+1,此包发送完毕, # 客户端和服务器进入ESTAB_LISHED(TCP链接成功)状态,完成三次握手。
#### 一、第一次挥手 # 首先,客户端发送一个FIN,用来关闭客户端到服务器的数据传送,而后等待服务器的确认。其中终止标志位FIN=1,序列号seq=u。 #### 二、第二次挥手 # 服务器收到这个FIN,它发送一个ACK,确认ack为收到的序号加一。 #### 三、第三次挥手 # 关闭服务器到客户端的链接,发送一个FIN给客户端。 #### 四、第四次挥手 # 客户端收到FIN后,并发回一个ACK报文确认,并将确认序号seq设置为收到序号加一。 # 首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。
TCP面向链接(如打电话要先拨号创建链接);UDP是无链接的,即发送数据以前不须要创建链接
TCP提供可靠的服务,也就是说,经过TCP链接传送的数据,无差错,不丢失,不重复,且按序到达; UDP尽最大努力交付,即不保证可靠交付
Tcp经过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。
UDP具备较好的实时性,工做效率比TCP高,适用于对高速传输和实时性有较高的通讯或广播通讯。
每一条TCP链接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通讯
TCP对系统资源要求较多,UDP对系统资源要求较少。
注:UDP通常用于即时通讯(QQ聊天 对数据准确性和丢包要求比较低,但速度必须快),在线视频等
tcp/udp相关协议
TCP: STMP, TELNET, HTTP, FTP
2.UDP: DNS,TFTP,RIP,DHCP,SNMP
1.是一种在单个TCP链接上进行 全双工通讯(又称为双向同时通讯,即通讯的双方能够同时发送和接收信 息的信息交互方式。)的协议。
2.WebSocket使得客户端和服务器之间的数据交换变得更加简单,容许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只须要完成一次握手,二者之间就直接能够建立持久性的链接,并进行双向数据传输。
栈是一种数据集合,能够理解为只能在一端进行插入或删除操做的列表
后进先出 栈有栈顶和栈底
进栈(压栈):push
出栈:pop
取栈顶:gettop
匹配括号是否成对出现
def check_kuohao(s): stack = [] for char in s: if char in ['(','[','{']: stack.append(char) elif char == ')': if len(stack)>0 and stack[-1] == '(': stack.pop() else: return False elif char == ']': if len(stack) > 0 and stack[-1] == '[': stack.pop() else: return False elif char == '}': if len(stack) > 0 and stack[-1] == '{': stack.pop() else: return False if len(stack) == 0: return True else: return False print(check_kuohao('(){}{}[]')) #True
队列是一个数据集合,仅容许在列表的一端进行插入,另外一端进行删除
插入的一端称为队尾(rear),插入动做叫进队或入队
进行删除的一端称为对头(front),删除动做称为出队
队列性质:先进先出(First-in, First-out)
双向队列:队列的两端都容许进行进队和出队操做
导入: from collectios import deque
建立队列:queue = deque(li)
进队: append
出队: popleft
双向队列队首进队:appendleft
双向队列队尾出队:pop
链表中每一个元素都是一个对象,每一个对象称为一个节点,包含有数据域key和指向下一节点的指针next,经过各个节点间的相互链接,最终串联成一个链表
单链表第一个节点没有前驱,最后一个节点没有后继。
class Node(object): def __init__(self, val): self.val = val self.next = None def list_reverse(head): if head == None: return None L, R, cur = None, None, head # 左指针、有指针、游标 while cur.next != None: L = R # 左侧指针指向之前右侧指针位置 R = cur # 右侧指针前进一位指向当前游标位置 cur = cur.next # 游标每次向前进一位 R.next = L # 右侧指针指向左侧实现反转 cur.next = R # 当跳出 while 循环时 cur(原链表最后一个元素) R(原链表倒数第二个元素) return cur if __name__ == '__main__': ''' 原始链表:1 -> 2 -> 3 -> 4 反转链表:4 -> 3 -> 2 -> 1 ''' l1 = Node(1) l1.next = Node(2) l1.next.next = Node(3) l1.next.next.next = Node(4) l = list_reverse(l1) print l.val # 4 反转后链表第一个值4 print l.next.val # 3 第二个值3
双链表中每一个节点有两个指针:一个指针指向后面节点、一个指向前面节点
本质和单向联链表同样,但循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。
数组的定义
所谓数组,就是相同数据类型的元素按必定顺序排列的集合
在Java等其余语言中并非全部的数据都能存储到数组中,只有相同类型的数据才能够一块儿存储到数组中。
由于数组在存储数据时是按顺序存储的,存储数据的内存也是连续的,因此他的特色就是寻址读取数据比较容易,插入和删除比较困难。
python中的list是python的内置数据类型,list中的数据类没必要相同的,而array的中的类型必须所有相同。
在list中的数据类型保存的是数据的存放的地址,简单的说就是指针,并不是数据
这样保存一个list就太麻烦了,例如list1=[1,2,3,'a']须要4个指针和四个数据,增长了存储和消耗cpu。
哈希表(也叫散列表),根据关键值对(Key-value)而直接进行访问的数据结构。
它经过把key和value映射到表中一个位置来访问记录,这种查询速度很是快,更新也快。
而这个映射函数叫作哈希函数,存放值的数组叫作哈希表
http://www.javashuo.com/article/p-qqhiwvjk-r.html
运行python的时候,咱们都是在建立并运行一个进程。像Linux进程那样,一个进程能够fork一个子进程,并让这个子进程exec另一个程序
在Python中,咱们经过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个建立子进程的函数,这些函数分别以不一样的方式建立子进程,因此咱们能够根据须要来从中选取一个使用
另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通讯。
Popen对象建立后,主程序不会自动等待子进程完成。咱们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block)
将多个子进程的输入和输出链接在一块儿
subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走
若是须要使用SSH从一个平台链接到另一个平台,进行一系列的操做时,
好比:批量执行命令,批量上传文件等操做,paramiko是最佳工具之一。
paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的链接
支持多平台 如Linux, Solaris, BSD,MacOS X, Windows等
通配符 ●
做用:● 能够匹配除换行符之外的任意一个字符串
转义字符 ╲
做用:能够将其余有特殊意义的字符串以本来意思表示
注:若是想对反斜线(\)自身转义可使用双反斜线(\\)这样就表示’\’
字符集
做用:使用中括号来括住字符串来建立字符集,字符集可匹配他包括的任意字串
①‘[pj]ython’ 只可以匹配‘python’ ‘jython’
② [a-z] 可以(按字母顺序)匹配a-z任意一个字符
③ [a-zA-Z0-9] 能匹配任意一个大小写字母和数字
④ ^abc 能够匹配任意除a,b和c 以外的字符串
管道符
做用:一次性匹配多个字符串
例如:’python|perl’ 能够匹配字符串‘python’ 和 ‘perl’
.最经常使用的匹配方法
\d 匹配任何十进制数;它至关于类 [0-9]。 \D 匹配任何非数字字符;它至关于类 0-9。 \s 匹配任何空白字符;它至关于类 [ fv]。 \S 匹配任何非空白字符;它至关于类 fv。 \w 匹配任何字母数字字符;它至关于类 [a-zA-Z0-9_]。 \W 匹配任何非字母数字字符;它至关于类 a-zA-Z0-9_。
\w* 匹配全部字母字符
\w+ 至少匹配一个字符
import re
#匹配时忽略大小写
print(re.search("[a-z]+","abcdA").group()) #abcd
print(re.search("[a-z]+","abcdA",flags=re.I).group()) #abcdA
sys.argv 返回执行脚本传入的参数
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操做系统平台名称
import os # 当前工做目录,即当前python脚本工做的目录路径 print(os.getcwd()) # C:\Users\admin\PycharmProjects\s14\Day5\test4 # 当前脚本工做目录;至关于shell下cd os.chdir("C:\\Users\\admin\\PycharmProjects\\s14") os.chdir(r"C:\Users\admin\PycharmProjects\s14") print(os.getcwd()) # C:\Users\admin\PycharmProjects\s14 # 返回当前目录: ('.') print(os.curdir) # ('.') #4 获取当前目录的父目录字符串名:('..') print(os.pardir) # ('..') # 可生成多层递归目录 os.makedirs(r'C:\aaa\bbb') # 能够发如今C盘建立了文件夹/aaa/bbb # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.removedirs(r'C:\aaa\bbb') # 删除全部空目录 # 删除单级空目录,若目录不为空则没法删除,报错;至关于shell中rmdir dirname os.rmdir(r'C:\aaa') # 仅删除指定的一个空目录 # 列出指定目录下的全部文件和子目录,包括隐藏文件,并以列表方式打印 print(os.listdir(r"C:\Users\admin\PycharmProjects\s14")) # 删除一个文件 os.remove(r'C:\bbb\test.txt') # 指定删除test.txt文件 # 重命名文件/目录 os.rename(r'C:\bbb\test.txt',r'C:\bbb\test00.bak') # 获取文件/目录信息 print(os.stat(r'C:\bbb\test.txt')) # 运行shell命令,直接显示 os.system("bash command") # 获取系统环境变量 print(os.environ) # environ({'OS': 'Windows_NT', 'PUBLIC': …………. # 返回path规范化的绝对路径 print(os.path.abspath(r'C:/bbb/test.txt')) # C:\bbb\test.txt # 将path分割成目录和文件名二元组返回 print(os.path.split(r'C:/bbb/ccc')) # ('C:/bbb', 'ccc') # 不管linux仍是windows,拼接出文件路径 put_filename = '%s%s%s'%(self.home,os. path.sep, filename) #C:\Users\admin\PycharmProjects\s14\day10select版FTP\home
函数 | 描述 |
---|---|
asctime([tuple]) | 将时间元组转换为字符串 |
localtime([secs]) | 将秒数转换为日期元组(转换成本国时区 |
mktime(tuple) | 将时间元组转换为本地时间 |
time() | 获取当前时间戳 |
时间戳 1970年1月1日以后的秒, 即:time.time()
格式化的字符串 2014-11-11 11:11, 即:time.strftime('%Y-%m-%d')
结构化时间 元组包含了:年、日、星期等... time.struct_time 即:time.localtime()
import datetime
#一、datetime.datetime获取当前时间
print(datetime.datetime.now())
#二、获取三天后的时间
print(datetime.datetime.now()+datetime.timedelta(+3))
#三、获取三天前的时间
print(datetime.datetime.now()+datetime.timedelta(-3))
#四、获取三个小时后的时间
print(datetime.datetime.now()+datetime.timedelta(hours=3))
#五、获取三分钟之前的时间
print(datetime.datetime.now()+datetime.timedelta(minutes = -3))
import datetime
print(datetime.datetime.now()) #2017-08-18 11:25:52.618873
print(datetime.datetime.now().date()) #2017-08-18
print(datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")) #2017-08-18 11-25-52
时间戳转换成datetime对象
# datetime.datetime.fromtimestamp(1520561646.8906238)
datetime.datetime(2018, 3, 9, 10, 14, 6, 890624)