变量的数据类型可以随时改变;多行注释 '''
type(a) //测试类型;
print(value,...,sep=,end=,file=sys.stdout,flush=Falsh);
f = open("poe.txt","w") // file = f print完后 f.close()
#coding:utf-8 //py2.7中文
关键字:None,False,True,del,elif,nonlocal,pass,raise,
内置函数:all(),any(),bin(),bool(),bytearray(),callable(),chr(),classmethod(),cmp(),compile(),complex(),delattr(),dict(),dir(),divmod(),enumerate(),eval(),execfile(),file(),filter(),float(),format(),frozenset(),getattr(),globals(),hasattr(),hash(),help(),hex(),id(),input(),int(),isinstance(),issubclass(),iter(),len(),list(),locals(),long(),map(),max(),memoryview(),min(),next(),object(),oct(),ord(),pow(),property(),range(),raw_input(),reduce(),reload(),repr(),reversed(),zip(),round(),set(),setattr(),slice(),sorted(),staticmethod(),str(),sum(),super(),tuple(),staticmethod(),str(),sum(),super(),tuple(),type(),unichr(),unicode(),vars(),xrange(),Zip(),))import__(),apply(),buffer(),coerce(),intern();
复数:Jj表示虚部;两个空格在一起就拼接;s = "heelo" "world"
py要求字典的key必须是不可变的;
p = 3.0
py中的空值为None;
str(p) //转数据为字串,repr(p) //一样的,repr()是函数,转换出的字串带引号;
input();用户输入
长串用\可以续行; 可以用'''wwwwww '''包含也可以
原始字串r'xxxxxx';
字节串:bytes; py3增,只负责以字节(二进制格式)序列来记录数据;
如果字符串内容是ASCII,前面加b"xxx"来构建,或调用byte();默认utf-8;
调用字符串本身的encode()方法将字串按指定字符集转换成字节串;
将bytes对象解码成字串,调用.decode('utf-8');
格式化:"xxxxxxx%s" % string; //%s 字串 %d 10进制小数 %f浮点
字符串加下标分解string[1] //可以为负数,然后分片[:3]
[2:8:3];从2开始,到8,步长为3;
'a' in 'dda' //True 注意in语法
dir()列出类或模板的全部内容,包括函数,方法,类,变量;
title()大写;lower(),upper()
删除空白:strip(),lstrip(),rstrip()
startswith(),endswith(),find(),index()
str.maketrans('abc','122') //创建翻译映射表
split():分割字串
join() 将多个短语连接成字符串
除法5/2 = 2.5 // 5//2 = 2 地板除;
5**2 //开方 =25
位运算:&;|; ^ 上尖异或; ~取反 << >> 移位;
~-5 : -5的补码,负数以补码存在,计算方法为:原码除符号位外:各位求反,末位加1;得到补码,正数补码和原码相同;
左移N位就相当于乘2的N次方,右移N位则相当于除以2的N次方;
可以用+=等一些赋值运算符;
is not 也是运算符;!=不等于 ; ==等于 <= 小于等于;
==比较变量的值,is要求两个变量引用同一对象;
time.gmtime() //结构变成tuple了;
逻辑: and or not
三元:(条件真值)if 条件 else (条件假)
in ,not in
-------------------------
程序把多个值赋给一个变量时,py会自动将多个值封装成元组,这种功能被称为序列封包;程序允许将序列(元组,列表)直接赋值给多个变量,此时序列的各元素会被依次赋值给每个变量(要求序列的元素个数和变量个数相等),这种功能被称为序列解包;
tuple(range(1,10,2)) //1,3,5,7,9
first,second,*rest = range(10) // 用*表示最后所有的;
c_list = list(range(4,20,3));
list.append() 既可以接收单个值,也可接收元组,列表等。
list.extend() 追加列表中的元素;
del a_list[2] //删第3个元素;
del name ; //删变量
remove(),clear() //清空,删除;
修改则通过[]索引,正负均可;还可以切片赋值; b[1:3] = ['a','b']
.count()统计元素在列表中出现的次数;index()出现的位置;pop(),reverse(),sort()
字典:score= {'math':90,'eng':91}
score={"math"=29} //score['math'] //可以用[]引用key获取value
列表不允许对不存在的索引赋值,但字典允许直接对不存在的key赋值;
.get() 跟key,返回value;
update()有覆盖,无则添加;
items()获取字典中的所有key-value对; keys(),values()
a.pop(key); //key出列,返回key的value,并删;
popitem()用于随机弹出字典中的一个key-value对;
a.fromkeys([1,2,3]) //不是a增加,而是产生一个新map; key为123,值为none;
'book name :%(name),%(price)'
print(temp % book) // book的字典包括name,price则字符串可以;原单个是%s,这个是具名的%(map key名) % mapName;
if不要忘记结尾:冒号;下面会被转为假:False,None,0,"",(),[],{};
空语句:pass;
assert 断言; 为真不计;为假出错
for in 字符串|范围|集合等;
如for key,value in a.items(): //循环字典;
py的循环可以使用else块,条件为假的时候执行;
类型推导返回的是列表:
[x*x for x in rage]
[x * x for x in range if x % 2 == 0]
[(x,y) for x in range(5) for y in range(4)] 双重循环,返回[(0,0,(0,1)...]
zip : a = ['a','b','c'] b = [1,2,3] ; zip(a,b)
[x for x in zip(a,b)]// dict(zip(a,b)
典型用法:用一个列表装名字,用一个列表装价格;然后zip后,名字对应价格对;
reversed()反转函数;
sorted(a,reverse=True)
逆向参数收集:指的是在程序己有列表,元组,字典等对象的前提下,把它们的元素执开后传给函数的参数;
def test(name,message); // test(*mylist) //把list列表分解成name,message赋值;
globals(),locals(),
vars(object) //if obj is null,equal locals()
使用全局变量 global name
nonlocal name : 函数的函数中上一级函数中的变量,用于闭包权限;
c = lambda n:n*n
map(func,ite,...) //根据指定的函数产生序列;
map(square,[1,2,3]) //123的平方列表;
实例方法的第一个参数self.特殊方法:__init__;双划线的方法均有特殊意义;
p = person(); //构造对象无须使用new;
类中:self.name = name;
为对象动态增加方法:1.先定义一个函数;2.把p.foo = info 把对象的.foo方法,用函数名赋值给对象,就给对象动态增加了一个方法;3.python不会自动self,需要手动一下:p.foo(p); //给info(self)中的self赋值;也可以from types import MethodType;
p.intro = MethodType(intro_func,p);
u= User() ; User.walk(u) //相当于把u给了self.
类方法与静态方法: @classmethod, @staticmethod; //后面跟方法函数
@符:1将被修饰的函数(函数B)作为参数传给@符号引用的函数(函数A)
2.将函数B替换(装饰)成第1的返回值;
定义属性:property();传入四个参数:getter,setter,del,doc;
class classname :
size = property(getsize,setsize,delsize,'说明’)
rect.size = 9,7 //调用setsize(w,h)为rect赋值;
print(rect.size)//调用getsize返回w,h;
del rect.size //调用delsize;
还可以使用
@property
def state(self)
@state.setter
@property
def is_dead(self):
继承:
class Apple(Fruit,Food):
pass;
如果子类重写父类的构造方法,那么子类的构造方法必须调用父类的构造方法。
调用父类方法:super()
__slots__属性的值是一个元组,该元组的所有元素列出了该类的实例允许动态添加所有属性名和方法名。只能对当前类起作用,对实例动态添加不能限制;
__slots__ = ('wak','age','name')
d.walk = MethodType(lambda self:print('test')),
使用type给对像增方法:
Dog = type('Dog',(object,),dict(walk=fn,age=8))
type参数1:创建的类名,2.继承父类集,3该字典对象为该类绑定的类变量和方法。
p153.使用metaclass
检测类型:issubclass(),isinstance();
枚举:from enum import Enum # 继承枚举类
class color(Enum): YELLOW = 1
try:
except Exce:
except (IndexError,ValueError): 捕获多种异常语法
except Exception as e:
python的所有异常都从BaseException派生而来,异常也可以用else;
finally:最后;
raise语句引发异常
引入异常分析模块:
import traceback
except: traceback.print_exc(),traceback.print_exc(file=open('log.txt','a'))
__repr__() //默认总是类名+object at +内存地址;
析构方法:__del__;
__dir__列出该对象的内部所有属性(包括方法)名;__dict__属性用于查看对象所有属性名和属性值组成的字典;
__getattribute__(self,name):当程序访问对象的name属性时被自动调用;
__getattr_(self,name):访问对象的name属性且该属性不存在时被自动调用;
___setattr__(self,name,value) 赋值时调用;
__delattr__(self,name):程序删除时使用;
检测对象是否包含某项方法和属性:
hasattr(obj,name);
getattr(obj,name,[default]):获取object对象中名为name的属性值;
setattr(obj,) 将obj的name属性设置为value;//设置不存在的属性,即为对象添加属性;
__call__判断到底是方法来是属性,即是否可调用;返回True,False;
序列相关方法:__len__,__getitem__(self,key):获取指定索引对应的元素;
__contains_(self,item):判断是否包含某元素
_setitem__(self,item) : 该方法设置指定索引对应的元素;
__delitem__(self,key):该方法删除指定索引对应的元素;
__iter__(self):返回一个迭代器;迭代器必须包含一个__next__()方法,该方法返回迭代器的下一个元素;
__reversed__(self):该方法主要为内建的反转函数提供支持;
yield生成器的语句的作用有两点:yield与函数相关联,不能单独定义语句;
每次返回一个值,类似于return;
冻结执行,程序每次执行到yield语句的时候就会被暂停;
在程序被yield语句冻结之后,当程序再次调用next()函数获取生成器的下一个值时,程序才会继续向下执行;
可以使用list()将生成器转换成列表;
生成器:使用for类型生成器类型推断,使用带yield语句的生成器函数;
还可以为生成器提供值,通过这种方式让生成器与外部程序动态交换数据;send()与next()函数功能相似,获取生成器所生成的下一个值,并将生成器冻结在yield语句处,但send()方法可以接收一个参数,该参数会发给生成器函数;
在生成器内部,程序可以通过yield表达式来获取send()方法所发送的值,这意味着此时程序应该使用一个变量来接收yield语句的值;外部程序通过使用send()方法发送数据,生成器函数使用yield语句接收数据;
n = yield *n // 这个变量是用来接收生成器所发送的值的;
py要求生成器第一次调用send()方法时只能发送None参数的原因;
类似于类的运算符重载:在类中实现这些方法:实现加减乘除大于小于等;object.__and__,object.__add__,object.__lt__(self,other),object.__eq__(self,other);(self,other);重载了这些,相当于x+y对类;
生成器:每次执行yield就返回,下次执行yield的下一条语句,然后yield返回值;
一元单目的重载方法:objcet.__neg__(self):求负; __invert__(self): 取反~;
类型转换:object.__bytes__(self),__int__(self),__float__(self)
__repr__()代表自我描述,用print()会调用__repr(),而__str__()方法则只有在显式调用str()函数时才会起作用;
__format__(self,format_spec):对应于调用内置的format()函数将对象转换成格式化字符串;
__hash__,__abs__,round__,__trunc__;__floor__(self),__ceil__(self);
定义模块:module1.py的模块名就是module1;说明文档在第一行'''
模块中,__all__变量:只有该列表中的程序单元才被显示出来;
__all__ = ['hell','work']
包:就是文件夹,有__init__.py文件,该文件可以用于包含多个模块源文件;
from . import print_shape //从当前包中导入print_shape模块;
os.name
random.randint(a,b),random.choice(seq),random.random(),random.uniform(a,b)
random.shuffle().
json的key-value在javaScript中是一个对象,在python中是dict对象;
有序集合,在python中对应列表;
json.dump(),dumps():将对象转换为json,并返回;单数用于从文件导入json;
load(),从fp流读取json字串;
loads()将json字串恢复成json对象;
json->python: load或loads()
python->json : dump,dumps()
json.JSONEncoder().encode({"names":(xxx,yy)}); //把js编码成python对象;
正则RE: re.compile('abc') p.search("wwww.abc.com")
re.search('ab','abcde') //由于编译,则有更好的性能及可复用;
re.match(pattern,string,flags=0) //从字串开始来匹配正则表达式;注意,从开始匹配
re.search() 扫描整个字串;只返回一处
re.findall(),finditer()返回所有出现的多处,iter可以转换为列表;
re.fullmatch():该函数要求整个字串能匹配pattern
re.sub:替换,后面接替换次数;默认全替换
r(?P<lang>\w+ : ?P表示为该组起名为<lang>
flags= re.A,只允许ASCII,去掉汉字;
re.split()用RE分割;
re.purge()清除缓存;
re.escape(pattern):对模式中除ASCII,数值,下画线之外的其他字符进行转义;
re.U匹配所有unicode字符;
re.S 让点能匹配包括换行符在内的所有字符;
re.M 多行
re.I 忽略大小写,re.A 只匹配ASCII
* 0次或多次,+:一次或多次;?零次或1次;
.匹配除换行\n之外的任何字符
\w : 匹配所有单词,\W非单词字符;
\S :非空白字符,小写,空白;
\d :匹配所有数字 ,\D匹配非数字;
[^]:表示求否定的,不放在方括号里也可以表示开头;
\b匹配单词的边界,即只能匹配单词前后的空白;
\B不在单词前后的空白
\A字串开头,\Z只匹配字串的结尾;仅用于最后的结束符;
(?P<name>exp):匹配exp表达式并捕获成命名组,该组的名字为name,后面可通过(?P=name)来引用前面捕获的组;
print(re.search(r'(?P<tag>\w)>\w+</(?P=tag)>',<h3>xxx</h3>))
?:exp 匹配但不捕获,就是不能用\1来引用结果集;
默认情况下,正则是贪婪模式,尽可能多的匹配字符,只要在频度限定之后加加天个?,就变成了勉强模式,尽可能少的匹配字符;如.+?
set无序不重复;使用{}创建集合;
from collections import deque;
append,appendleft,添加,pop,popleft:出队;
clear();rotate()
from heapq import* 堆;
from collections import ChainMap
cm = ChainMap(a,b,c)将三个dict链在一起,变成一个大的dict
from collections import defaultdict 带默认值的dict,如果访问不存在的值,则返回default_factory属性0。
from collections import namedtuple;
Point = namedtuple('Point',['x','y']);
p = Point(11,y=12)
a,b = p;
------------------
from collections import OrderedDict
dx = OrderedDict(b=5,c=2,a=7)//带顺序的字典,先添加的前面,后添加的后面;
functools模块:函数装饰器和便捷的功能函数:
pathlib,os.path来操作各种路径;PurePath:代表并不访问实际文件系统的“纯路径”,简单来说,PurePath只是负责路径字符串执行操作,至于该字符串是否对应实际的路径,它并不关心,PurePath有两个子类,即PurePosixPath,PureWindowPath分别代表Unix风格的路径和windows的路径;
p = Path('.') for x in p.iterdir(): print(x)
p.glob("**/*.py")
from pathlib import *
p = Path('a.txt')
result = p.write_text('xxxxxx')
content = p.read_text(encoding = 'GBK')
p.read_bytes()
os.path.abspath('abc.txt')
os.path.commonprefix(['/usr/lib','/usr/local/lib # usr/l 前面相同部分
os.path.commonpath();获取共同路径;
os.path.exists('a.txt')
time.ctime(os.path.getatime('os.path_test.py')))
os.path.dirname()
os.path.getmtime('a.txt')//获取创建时间
os.path.getsize()
os.path.isfile(),os.path.isdir()
os.path.samefile() //两个文件是不是一样的
import fnmatch
fnmatch.match('*.py')
fnmatch.filter(names,'[ac].py')
f.closed f.mode f.name 都可以显示文件的打开模式和文件名;
rb+代表二进制读写模式
open(t.ab,r,true) //第三个参数为是否打开缓冲区
不知道字符集,使用二进制模式读取,然后用bytes的decode()方法恢复字符串。
二进制rb读后,f.read().decode('utf-8')
import codecs
f = codecs.open()
fileinput.input(files=('in.txt','b,txt')):
for line in sys.stdin:
print('用户输入',line,end='')
text = sys.stdin.read() //ctrl+d 结束
py提供with语句来管理资源关闭,with语句会自动关闭文件,只要一个类实现了__enter__(),和__exit__()方法,就可以通过with语句管理;
linecache模块:
linecache.getline()
linecache.clearcache() 清空缓存
linecache.checkcache() 检测缓存是否有效;
seek(),移动文件指针,tell()判断指针的位置;
write(),writelines():
os.linesep
('text').encode('utf-8') //写文件时以uft8编码;
os.getcwd() 获取当前目录
os.chdir(path) os.fchdir(fd)通过文件描述符改变当前目录
os.chroot(),os.listdir(),os.mkdir(),os.makedirs()//可以递归创建目录
os.rmdir(),os.removedirs()//递归删除目录
os.rename(),os.renames()//可以递归重命名目录
os.access(path,mode):检查权限os.F_OK,os.R_ok,os.W_ok,os.X_OK
os.chmod(path,mode) stat.IWRITE:可写;
os.chown,os.fchmod(fd.mode)
os.fchown()
os.read(fd,n)
os.write()
os.close()
os.lseek()
os.fdopen()
os.closerange(fd_low,fd_high)
os.dup(fd)复制文件描述符;
os.dup2(fd,fd2)将一个文件描述符FD复制到另一个文件描述符FD2中
os.ftruncate()截取文件到指定长度
os.remove()删文件;
os.link() 创建从src到dst的硬链接;
os.symlink(src,dst):创建从src到dst的符号链接,对应于win的快捷方式;
import tempfile
tempfile.TemporaryFile()创建临时文件;
tempfile.NamedTemporaryFile() 临时文件,有文件名
tempfile.SpooledTemporaryFile()创建临时文件,先输出到内存,直到超过max_size才会真正写到物理磁盘;
tempfile.TemporaryDirectory(suffix=Nono,prefix=None,dir=None):生成临时目录;tempfile.gettempdir()获取系统临时目录。
import sqlite3
sqlite3.apilevel
线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程,线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源;一个线程可以创建和撤销另一个线程;线程共享包括进程的代码段、进程的公有数据等,利用这些共享的数据,线程之间很容易实现通信;
提供了二个线程模块:_thread,threading,推荐使用threading模块;
使用或继承Thread类;__init__(self,group=None,target=None,name=None,args=(),kwargs=None,*,daemon=None)
t1=threading.Thread(target=action,args=(100,)) // t1.start()
threading.current_thread() 返回正在执行的线程对象
getName()该方法返回调用它的线程名字,通过setName(name)方法为线程设置名字,默认主线程为MainThread,Thread-1,Thread-2.
通过继承的方式:
1.定义Thread类的子类,并重写该类的run()方法,run()方法代表要完成的任务,重写run();2.创建子类线程对象,3.start();
class FkThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.i = 0;
def run(self):
...
启动线程使用start()方法,而不是run,永远不要调用线程对象的run()方法;调用start(),系统会把run()当成线程执行体来处理,否则就当成普通函数;start()不能重复调用;
一些小型设备如手机等可能采用协作式调度策略,在这样的系统中,只有当一个线程调用了它的sleep()或yield()方法后才会放弃其所占用的资源,也就是必须由该线程主动放弃其所占的资源;
线程是否死亡:调用is_alive()方法;
join()方法:在执行流中调用join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完成;
join()方法通常由使用线程的程序调用,以将大问题划分成许多小问题,并为每个小问题分配一个线程,当所有的小问题都得到处理后,再调用主线程来进一步操作;
t.daemon = True;t.start() //设置为后台线程;
time.sleep(sec);
同步锁
threading.Lock,threading.RLock:可重入锁;几次锁,几次释放;成对出现;
self.lock.acquire()
try:
使用锁
finally:
self.lock.release()
线程安全:该类的对象可以被多个线程安全的访问;
self.lock = threading.RLock() //给类加一个lock可重入锁;
self.lock.acquire() //加锁
try:..... finally: self.lock.release() //在finally块中释放锁,避免异常死锁;
双版本出现的原因:单线程中使用线程不安全版本以保证性能,多线程中使用线程安全;
避免出现死锁:避免多次锁定,具有相同的加锁顺序,使用定时锁;进行死锁检测
Condition线程通信,可以让那些己经得到Lock对象却无法继续执行的线程翻译Lock对象,Condition对象也可以唤醒其他处于等待状态的线程;
方法:Condition.acquire(),调用Condition关联的Lock的acquire(),release()
.wait():导致当前线程进入conditon的等待池等待通知并释放锁,直到其他线程调用该condition的notify()或notify_all()方法唤醒该线程,可以传入time秒上限;
.notify()唤醒在该condition等待池的单个线程并通知它,收到通知的线程将自动调用acquire()方法尝试加锁,若所有线程都在该Condition等待池中等待,则会任意选择唤醒其中一个线程;
.notify_all()唤醒在该condition等待池中所有线程并通知它们;
queue模块控制线程通信:queue.Queue(maxsize=0)如果队列大小达到上限,就会加锁;再加就会阻塞;直到队列中的元素被消费;
queue.LifoQueue(maxsize)LIFO先进后出,顺序不同;
PriorityQueue(maxsize=0): 代表优先级队列;
Queue.qsize()返回队列的实际大小;
Queue.empty():判断队列是否为空;
Queue.full()判断队列是否己满;
PriorityQueue(maxsize=0):优先权队列
.put()插入元素
.get()取出元素;
Queue.put_nowait(item):向队列中放入元素,不阻塞;
将Condition对象与Lock对象组合使用,可以为每个对象提供多个等待集,因此,Condition对象总是需要有对应的Lock对象;
Event是一种非常简单线程通信机制,一个线程发出一个Event,另一个线程可以通过该Event被触发;is_set(),set()把event的内部旗标设置为True,并唤醒所有处理等待状态的线程
,clear():该方法将Event的内部旗标设置为False,通常接下来会调用wait()方法来阻塞当前线程;
.wait()阻塞当前线程;
线程池:基类:concurrent.futures模块的Excutor,两个子类:ThreadPoolExecutor,ProcessPoolExecutor,一个线程池,一个进程池;
方法:submit(),map(),shutdown()
Future提供如下方法:cancel(),取消,如正在执行,不可取消;
cancelled(),是否被成功取消?
running()正在执行?
done()己完结(成功,取消均可)?
exception(),没异常则None;
add_down_callback(fn):为该Future代表的线程任务注册一个“回调函数”;当任务成功完成时,触发该fn()
使用线程池执行任务:
1.调用ThreadPoolExecutor类构造一个线程池;
2.定义普通函数作为线程任务
3.调用ThreadPoolExecutor对象的submit()方法来提交线程任务。
4.当不想提交任务时,调用ThreadPoolExecutor对象的ShutDown()方法来关闭线程池;
from concurrent.futures import ThreadPoolExecutor
pool = ThreadPoolExecutor(max_works=2)
future1 = pool.submit(action,50)
future2 = pool.submit(action,520)
print(future1.down())....
print(future2.result())
pool.shutdown()
程序使用Future的result()方法来获取结果时,该方法会阻塞当前线程,如果没有指定timeout参数,当前线程将一直处于阻塞状态,直到Future代表的任务返回;如果不希望直接调用result()方法阻塞线程,则可以通过Future的add_done_callback()方法来添加回调函数;
----------------------------------------
from concurret.futures import ThreadPoolExecutor
import threading
import time
#定义一个准备作为线程任务的函数
def action (max) :
my sum = 0
for l 工n range (max) :
print(threading.current_thread() . name + ’’ + str(i))
my sum +=工
return my sum
#创建一个包含两个线程的线程池
with ThreadPoolExecutor(max workers=2) as pool:
#向线程池中提交一个任务, 50 会作为 action ()函数的参数
futurel = pool.submit( action , 50 )
#向线程池中再提交一个任务, 100 会作为 action ()函数的参数
future2 = pool.submit(action , 100)
def get_result (future):
print (future.result())
#为 futurel 添加线程完成的回调函数
futurel.add done callback(get result}
#为 future2 添加线程完成的回调函数
future2.add二done_callback(get_result}
print (’----------’ )
threading.local()返回一个线程局部变量,隔离多线程访问的竞争资源,从而简化多线程并发访问的编程处理;内部实现其实就是为每一个使用该变量的线程都提供一个变量副本,使每一个线程都可以独立改变自己的副本,而不会和其他的线程副本冲突,从线程的角度看,就好像每一个线程都完全拥有该变量一样;
mydata = threading.local(),线程局部变量和其他同步机制一样,为了解决多线程中对共享资源的访问冲突;线程局部变量是为了隔离多个线程的数据共享,从根本上避免多个线程之间对共享资源(变量)的竞争,也就不需要对多个线程进行同步;
from threading import Timer
t = Timer(10,func)//计时器,10秒后调用func函数
sched.scheduler类:任务调度器:
工 mport sched , time
import threading
#定义线程调度器
s = sched.scheduler()
#定义被调度的函数
---------------------------------
import sched,time
#定义线程调度器:
s = sched.scheduler()
s.enter(10,1,print_time) //10秒后执行print_time,优先级为1;
s.enter(5,2,print_time,argument=('位置参数',))
s.enter(5,1,print_time,kwargs={'name':'关键字参数'})
多进程;
pid = os.fork()
if pid==0:
print('子进程')
在windows下创建新进程:import multiprocessing
mp1.multiprocessing.Process(target=action,args=(100,))
mp1.start()
mp2= multiprocessing.Process(target=action,args=(100,))
mp2.start()
mp2.join()
也可以通过类继承:
1.定义子类继承Process,重写run()作为执行体
2.创建实例来调用start()启动;
class MyProcess(multiprocessing.Process):
def __init__(self,max):
self.max=max
super().__init__()
spawn:父进程启动一个全新的py解释器,子进程只能继承那些处理run()方法所必须的资源;效率比fork或forkserver方式低(win32默认);
forkserver:如果使用这种方式来启动进程,程序将会启动一个服务器进程,在以后的时间内,当程序再次请求启动新进程时,父进程都会连接到该服务器进程;请求由服务器进程来fork新进程;
import multiprocessing
import time
import os
def action(name='default'):
print (’( % s )进程正在执行,参数为: ’ % (os.getpid(), name))
time.sleep(3)
if name == 'name'
#创建包含 4 个进程的进程池
pool = multiprocessing.Pool(processes=4)
#将 action 分 3 次提交给进程池
pool.apply_async(action) //apply()方法的异步版本,不会阻塞;
pool.apply_async(action, args’位置参数’,)}
pool.apply_async(action, kwds={’ name 勺’关键字参数’}}
pool.close()关进程池,还有一个terminate立即中止进程池;
pool.join ()等所有进程完成
进程通信:两种:Queue:一个进程向Queue中放入数据,另一个从Queue中读取数据
Pipe:两个进程的管道,程序在调用Pipe()函数时会产生两个连接端,分别交给通信的两个进程,接下来进程即可以从该连接端读取数据,也可以向该连接端写入数据;
q = multiprocessing.Process(target=f,args=(q,))
p.start()
q.put(),q.get()
p.join()
使用pipe实现进程通信,程序会调用multiprocessing.Pipe()函数创建一个管道,该函数会返回两个PipeConnection对象,代表管道的两个连接端(一个管道连接两个连接端,分别用于连接通信的两个进程)。
pipConnection对象包含:send(obj)发送一个obj给管道另一端,另一端使用recv()接收;该obj必须是picklable(python序列化机制),一般不超过32M;
poll返回连接中是否还有数据可以读取;
send_bytes()发送字节数据;recv_bytes(),recv_bytes_into(buffer,offset)接收进缓冲
multiprocessing.current_process().pid
asyncore:异步网络库;asynchat:增强异步网络库,httplib,http.client:http库;xmlrpc,xmlrpc.server,xmlrpc.client;
import urllib
urllib.parse.urlparse('http://www.baidu.com')
fragment 对于 HTML 文档来说就是页面内的定位标识符,可以实现 HTML 页面内的定位。
parse_qs('name=k&age=18') // 解析查询字串,parse_qsl("age=18") //l是列表;
urljoin()
urllib.request.urlopen('http://www.baidu.com')
返回一个http.client.HTTPResponse对象,可调用read(),read(128) //后面跟字节;data.decode('utf-8') //将字节数据恢复成字符串。
with urlopen('xx') as f: //f.read(128) // print(data.decode('utf-8')
url.parse.urlencode({'name':'中文','password':'12'}) //生成url编码
t = request.Request(url="",data="参数",method='PUT') //t.status //状态
req = Request('http://www.baidu.com') // req.add_header('Referer','http://www.xxx')
http.cookiejar.CookieJar对象
from urllib.request import *
import http.cookiejar,urllib.parse
cookie_jar = http.cookiejar.MozillaCookieJar('a.txt')
cookie_processor = HTTPCookieProcessor(cookie_jar)
opener = build_openner(cookie_processor)
socket.accept()
socket.close()
socket.bind()
socket.connect(address)
socket.connect_ex()出错时不会抛出异常
socket.listen()
socket.makefile()创建一个和该socket关联的文件对象
socket.recv(),socket.recvfrom(),socket.recvmsg():该方法不仅接收自socket的数据,还接收来自socket的辅助数据,因此该方法的返回值是一个长度为4的元组(data,ancdata,msg_flags,address)
socket.recvmsg_into();同上,只是把接收到的数据,放入buffers中
socket.send(),TCP发送数据
socket.sendto(),UDP中发送数据
socket.shutdown(),sendfile()
c.addr = s.accept() //C为客户端socket对象,可以调用c.send()发送东西;
发送和接收都要指定编码:c.send('xxx'.encode('utf-8'))
s.recv(1024).decode('utf-8')
shutdown(how) //SHUT_RD(关输入部分,但是可以输出 ,SHUT_WR,关输出,可读
SHUT_RDWR:全关;
一般使用:sk.send(xxxx) sk.shutdown(socket.SHUT_WR) //关输出,sk.recv(1024).secode('utf-8'),最后.close()
selectors模块允许socket以非阻塞方式进行通信,selectors相当于一个事件注册中心,程序只要将socket的所有事件注册给selectors管理,当selectors检测到socket中的特定事件后,程序就可以调用相应的监听方法进行处理。
selectors支持两种事件:selectors.EVENT_READ:有数据可读时触发;
selectors.EVENT_WRITE:将要写数据时触发该事件;
import selectors;
sel = selectors.DefaultSelector()
sel.register(conn,selectors.EVENT_READ,read) //为conn的EVENT_READ事件注册read监听
sel.register(sock,selectors.EVENT_READ,accept)//为sel为sock的EVENT_READ注册事件;
s = socket.socket()
s.setblocking(False)
sel.register(s,selectors.EVENT_READ,read)
UDP: 1.SOCK_DGRAM,2.sendto,recvfrom()
TTL为1时,本地局域网中,32本站的网络上,64本地区,128本大洲;
pygame.image.save(),tostring(),fromstring(),frombuffer()来完成图片序列化操作;
resize(),scale2x(img)重设尺寸,放大2倍;
import csv
reader = csv.reader(f)
header_row = next(reader)
first_row = next(reader)
Scrapy: lxml,cssSelect,twisted;
1.cmd: scrapy shell http://www.baidu.com/
2.cmd: 设置代理:scrapy shell -s USER_AGENT="Mozilla/5.0'
3.shell后提示符变成>>> 可以使用response.xpath('测试’).extract()
4.编写items.py为要采集的字段设置类;
5.cmd生成spider:scrapy genspider job_positon "www.baidu.com"
---------------------------------------------------------------------------------------------
data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]
>>> _, shares, price, _ = data, //_任意变量名去占位;
first, *middle, last = grades //*语法获取
record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
name, email, *phone_numbers = record //用户有多个电话;
for tag,*args in records:
uname,*fields,homedir,sh = line.split(':')
from collections import deque
def search(lines, pattern, history=5):
previous_lines = deque(maxlen=history)
for line in lines:
if pattern in line:
yield line, previous_lines
previous_lines.append(line)
使用deque(maxlen=N)构造函数会新建一个固定大小的队列,当新的元素加入并且这个队列己满的时候,
最老的元素会被移除掉;
找最大或最小的N个元素:
import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
堆排序后放入列表:
>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
>>> import heapq
>>> heap = list(nums)
>>> heapq.heapify(heap)
>>> heap
堆数据结构最重要的特征是 heap[0] 永远是最小的元素。并且剩余的元素可以很
容易的通过调用 heapq.heappop() 方法得到
字典一个key对应多个值映射:d={‘a’:[1,2,3],'b':[4,5]}
defaultdict 的一个特征是它会自动初始化每个 key 刚开始对应的值.
d['a'].append(1) //一个key可以对应多个value;
from collections import OrderedDict //有序列表;
对字典排序求最大值,一般都是先zip后操作;
对字典求相同的key,值: a.keys()&b.keys()
a.keys()-b.keys()
a.items() & b.imtems()
切片对象:a = slice(5,50,3) //a.start,a.stop,a.step //item[a]
统计出现频率:from collections import Counter
word_counts = Counter(words)
tp_three = word_counts.most_common(3)//出现频率最高的三个词
word_counts['not'] 18 //not出现的次数;
通过关键字排序字典列表:operator模块的itemgetter函数:
from operator import itemgetter
rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_fname)
print(rows_by_uid)//排序
也支持多个字段排序:rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
通过字段分组:
from itertools import groupby
# Sort by the desired field first
rows.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('date')):
itertools.compress() ,它以一个 iterable
过滤:filter(),列表解析,还有:itertools.compress() 对象和一个相对应的 Boolean 选择器序列作
为输入参数。然后输出 iterable 对象中对应选择器为 True 的元素。
映射名称到序列元素:
from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'
re.split(r'[;,\s]\s*', line) //字符串分隔
re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text) //替换
在需要比较字符串的程序中使用字符的多种表示会产生问题。为了修正这个问题,
你可以使用 unicodedata 模块先将文本标准化:
>>> import unicodedata
>>> t1 = unicodedata.normalize('NFC', s1)
>>> t2 = unicodedata.normalize('NFC', s2)
>>> text.center(20,'*')
'****Hello World*****'
>>>
>>> name = 'Guido'
>>> n = 37
>>> s.format_map(vars())
'Guido has 37 messages.'
>>> s = 'Elements are written as "<tag>text</tag>".'
>>> import html
>>> print(s)
Elements are written as "<tag>text</tag>".
>>> print(html.escape(s))
Elements are written as "<tag>text</tag>".
>>> t = 'The prompt is >>>'
>>> from xml.sax.saxutils import unescape
>>> unescape(t)
'The prompt is >>>'
>>>
格式化输出单个数字的时候,可以使用内置的 format() 函数,比如:
>>> x = 1234.56789
>>> # Two decimal places of accuracy
>>> format(x, '0.2f')
'1234.57'
>>> format(x, ',')
'1,234.56789'
'The value is {:0,.2f}'.format(x)
>>> int('4d2', 16)
1234
>>> int('10011010010', 2)
1234
>>>
>>> x = 94522842520747284487117727783387188
>>> x.to_bytes(16, 'big')
b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
>>> x.to_bytes(16, 'little')
b'4\x00#\x00\x01\xef\xcd\x00\xab\x90x\x00V4\x12\x00'
>>>
>>> from fractions import Fraction
>>> a = Fraction(5, 4)
>>> b = Fraction(7, 16)
c.numerator //分子
c.denominator //分母
float(c) 转换成分母;
如果要获取 N 位随机位 (二进制) 的整数,使用 random.getrandbits() :
>>> random.getrandbits(200)
335837000776573622800628485064121869519521710558559406913275
>>>
random.seed() # Seed based on system time or os.urandom()
random.seed(12345) # Seed based on integer given
random.seed(b'bytedata') # Seed based on byte data
>>> from datetime import timedelta
>>> a = timedelta(days=2, hours=6)
>>> b = timedelta(hours=4.5)
>>> c = a + b
>>> c.days
2
>>> c.seconds
37800
>>> c.seconds / 3600
10.5
>>> c.total_seconds() / 3600
58.5
>>>
>>> from datetime import datetime
>>> a = datetime(2012, 9, 23)
>>> print(a + timedelta(days=10))
2012-10-03 00:00:00
>>>
>>> b = datetime(2012, 12, 21)
>>> d = b - a
>>> d.days
89
>>> now = datetime.today()
>>> print(now)
2012-12-21 14:54:43.094063
>>> print(now + timedelta(minutes=10))
2012-12-21 15:04:43.094063
>>>
datetime 模块已经足够了。如果你需要执行更加复杂的日期操作,比如处理时区,模糊时间范围,节假
日计算等等,可以考虑使用 dateutil 模块。
>>> from datetime import datetime
>>> text = '2012-09-20'
>>> y = datetime.strptime(text, '%Y-%m-%d')
>>> z = datetime.now()
>>> diff = z - y
>>> diff
datetime.timedelta(3, 77824, 177393)
>>>
pytz 模块一个主要用途是将 datetime 库创建的简单日期对象本地化。比如,下
面如何表示一个芝加哥时间的示例:>>> from datetime import datetime
>>> from pytz import timezone
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> print(d)
2012-12-21 09:30:00
>>>
>>> # Localize the date for Chicago>>> central = timezone('US/Central')
>>> # Convert to Bangalore time
>>> bang_d = loc_d.astimezone(timezone('Asia/Kolkata'))
>>> print(bang_d)
2012-12-21 21:00:00+05:30
>>>
迭代器:it = iter(iterms) //产生可迭代对象,next(it)
Python 的迭代器协议需要 __iter__() 方法返回一个实现了 __next__() 方法的
迭代器对象。
反向迭代仅仅当对象的大小可预先确定或者对象实现了 __reversed__() 的特殊
方法时才能生效。如果两者都不符合,那你必须先将对象转换为一个列表才行
排列组合:
>>> items = ['a', 'b', 'c']
>>> from itertools import permutations
>>> for p in permutations(items):
... print(p)
...
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
>>>
产生序列:
for idx, val in enumerate(my_list):
... print(idx, val)
>>> xpts = [1, 5, 4, 2, 10, 7]
>>> ypts = [101, 78, 37, 15, 62, 99]
>>> for x, y in zip(xpts, ypts)
with open('sorted_file_1', 'rt') as file1, \
open('sorted_file_2', 'rt') as file2, \
open('merged_file', 'wt') as outf:
for line in heapq.merge(file1, file2):
outf.write(line)
with open('somefile.txt', 'rt', encoding='latin-1') as f:
>>> g = open('hello.txt', 'rt', newline='')
with open('d:/work/test.txt', 'wt') as f:
print('Hello World!', file=f)
>>> s = io.StringIO()
>>> s.write('Hello World\n')
12
>>> print('This is a test', file=s)
15
>>> # Get all of the data written so far
>>> s.getvalue()
'Hello World\nThis is a test\n'
>>>
>>> # Wrap a file interface around an existing string
>>> s = io.StringIO('Hello\nWorld\n')
>>> s.read(4)
'Hell'
>>> s.read()
'o\nWorld\n'
>>>
io.StringIO 只能用于文本。如果你要操作二进制数据,要使用 io.BytesIO 类来
代替。比如:
>>> s = io.BytesIO()
>>> s.write(b'binary data')
>>> s.getvalue()
b'binary data'
>>>
需要注意的是, StringIO 和 BytesIO 实例并没有正确的整数类型的文件描述符。
因此,它们不能在那些需要使用真实的系统级文件如文件,管道或者是套接字的程序中使用。
from functools import partial
RECORD_SIZE = 32
with open('somefile.data', 'rb') as f:
records = iter(partial(f.read, RECORD_SIZE), b'')
for r in records:
...
这个例子中的 records 对象是一个可迭代对象,它会不断的产生固定大小的数据
块,直到文件末尾。要注意的是如果总记录大小不是块大小的整数倍的话,最后一个返回元素的字节数
会比期望值少。
用bytearray作缓冲区:
import os.path
def read_into_buffer(filename):
buf = bytearray(os.path.getsize(filename))
with open(filename, 'rb') as f:
f.readinto(buf)
内存映射一个二进制文件到一个可变字节数组中,使用 mmap 模块来内存映射文件。
import os
import mmap
def memory_map(filename, access=mmap.ACCESS_WRITE):
size = os.path.getsize(filename)
fd = os.open(filename, os.O_RDWR)
return mmap.mmap
return buf
import glob
pyfiles = glob.glob('somedir/*.py')
from fnmatch import fnmatch
pyfiles = [name for name in os.listdir('somedir')
if fnmatch(name, '*.py')]
默认情况下,所有的文件名都会根据 sys.getfilesystemencoding() 返回的文本
编码来编码或解码。
# Example of getting a directory listing
import os
import os.path
import glob
pyfiles = glob.glob('*.py')
# Get file sizes and modification dates
name_sz_date = [(name, os.path.getsize(name), os.path.getmtime(name))
for name in pyfiles]
for name, size, mtime in name_sz_date:
print(name, size, mtime)
# Alternative: Get file metadata
file_metadata = [(name, os.stat(name)) for name in pyfiles]
for name, meta in file_metadata:
print(name, meta.st_size, meta.st_mtime)
默认情况下,所有的文件名都会根据 sys.getfilesystemencoding() 返回的文本
编码来编码或解码。
给一个以二进制模式打开的文件添加 Unicode 编码/解码:
import urllib.request
import io
u = urllib.request.urlopen('http://www.python.org')
f = io.TextIOWrapper(u, encoding='utf-8')
text = f.read()
sys.stdout.encoding
如果你想修改一个已经打开的文本模式的文件的编码方式,可以先使用 detach()
方法移除掉已存在的文本编码层,并使用新的编码方式代替。下面是一个在 sys.stdout
上修改编码方式的例子:
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
>>> sys.stdout.encoding
'latin-1'
>>>临时文件
from tempfile import TemporaryFile
with TemporaryFile('w+t') as f:
# Read/write to the file
f.write('Hello World\n')
f.write('Testing\n')
# Seek back to beginning and read the data
f.seek(0)
data = f.read()
============
f = TemporaryFile('w+t')
# Use the temporary file
...
f.close()
==============
from tempfile import NamedTemporaryFile
with NamedTemporaryFile('w+t') as f:
print('filename is:', f.name)
--------------
为了创建一个临时目录,可以使用 tempfile.TemporaryDirectory()
from tempfile import TemporaryDirectory
with TemporaryDirectory() as dirname:
print('dirname is:', dirname)
--------------
使用 mkstemp() 和 mkdtemp() 来创建临时文件和目录
与串行端口的数据通信:
对于串行通信最好的选择是使用 pySerial 包 。
import serial
ser = serial.Serial('/dev/tty.usbmodem641', # Device name varies
baudrate=9600,bytesize=8,parity='N',stopbits=1)
ser.write(b'G1 X50 Y50\r\n')
resp = ser.readline()
序列化:
import pickle
data = ... # Some Python object
f = open('somefile', 'wb')
pickle.dump(data, f)
s = pickle.dumps(data)
# Restore from a file
f = open('somefile', 'rb')
data = pickle.load(f)
# Restore from a string
data = pickle.loads(s)
------------
import csv
with open('stocks.csv') as f:
f_csv = csv.reader(f)
headers = next(f_csv)
for row in f_csv:
# Process row //f_csv = csv.DictReader(f)
-----------
headers = ['Symbol','Price','Date','Time','Change','Volume']
rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800),
('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500),
('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000),
]
with open('stocks.csv','w') as f:
f_csv = csv.writer(f)
f_csv.writerow(headers)
f_csv.writerows(rows)
-------------------------------------
f_tsv = csv.reader(f, delimiter='\t')
--------------------------------------
xml:
from urllib.request import urlopen
from xml.etree.ElementTree import parse
# Download the RSS feed and parse it
u = urlopen('http://planet.python.org/rss20.xml')
doc = parse(u)
# Extract and output tags of interest
for item in doc.iterfind('channel/item'):
title = item.findtext('title')
date = item.findtext('pubDate')
link = item.findtext('link')
print(title)
print(date)
print(link)
print()
-----------------------------------
>>> from xml.etree.ElementTree import parse, Element
>>> doc = parse('pred.xml')
>>> root = doc.getroot()
>>> root
<Element 'stop' at 0x100770cb0>
>>> # Remove a few elements
>>> root.remove(root.find('sri'))
>>> root.remove(root.find('cr'))
>>> # Insert a new element after <nm>...</nm>
>>> root.getchildren().index(root.find('nm'))
1
>>> e = Element('spam')
>>> e.text = 'This is a test'
>>> root.insert(2, e)
>>> # Write back to a file
>>> doc.write('newpred.xml', xml_declaration=True)
>>>
------------------------------------------
对于任何涉及到统计、时间序列以及其他相关技术的数据分析问题,都可以考虑使
用 Pandas 库 。
>>> import pandas
>>> # Read a CSV file, skipping last line
>>> rats = pandas.read_csv('rats.csv', skip_footer=1)
>>> rats
------------------
为了接受任意数量的关键字参数,使用一个以 ** 开头的参数。
lambda x,y:x+y
如果需要减少某个函数的参数个数,你可以使用 functools.partial() 。partial()
函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。
def spam(a, b, c, d):
print(a, b, c, d)
>>> from functools import partial
>>> s1 = partial(spam, 1) # a = 1
>>> s1(2, 3, 4)
1 2 3 4
>>> s1(4, 5, 6)
1 4 5 6
>>> s2 = partial(spam, d=42) # d = 42
>>> s2(1, 2, 3)
1 2 3 42
>>> s2(4, 5, 5)
4 5 5 42
>>> s3 = partial(spam, 1, 2, d=42) # a = 1, b = 2, d = 42
>>> s3(3)
1 2 3 42
>>> s3(4)
1 2 4 42
>>> s3(5)
1 2 5 42
>>>
为了自定义字符串的格式化,我们需要在类上面定义 __format__() 方法。为了让一个对象兼容 with
语句,你需要实现 __enter__() 和 __exit__() 方法。
对于主要是用来当成简单的数据结构的类而言,你可以通过给类添加 __slots__
属性来极大的减少实例所占的内存。比如:
class Date:
__slots__ = ['year', 'month', 'day']
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
当你定义 __slots__ 后, Python 就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定
大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在 __slots__ 中列出的
属性名在内部被映射到这个数组的指定小标上。使用 slots 一个不好的地方就是我们不能再给实例添加
新的属性了,只能使用在__slots__ 中定义的那些属性名。
新增属性:
class Person:
def __init__(self, first_name):
self.first_name = first_name
# Getter function
@property
def first_name(self):
return self._first_name
# Setter function
@first_name.setter
def first_name(self, value):
@first_name.deleter
def first_name(self):
在现有方法上设置属性:name = property(get_first_name, set_first_name, del_first_name)
下面是一个示例类,它继承自 Person 并扩展了 name 属性的功能:
class SubPerson(Person):
@property
def name(self):
print('Getting name')
return super().name
@name.setter
def name(self, value):
print('Setting name to', value)
super(SubPerson, SubPerson).name.__set__(self, value)
@name.deleter
def name(self):
print('Deleting name')
super(SubPerson, SubPerson).name.__delete__(self)
接下来使用这个新类:
>>> s = SubPerson('Guido')
Setting name to Guido
>>> s.name
Getting name
'Guido'
>>> s.name = 'Larry'Setting name to Larry
>>> s.name = 42 //error
如果你仅仅只想扩展 property 的某一个方法,那么可以像下面这样写:
class SubPerson(Person):
@Person.name.getter
def name(self):
print('Getting name')
return super().name
定义抽象基类:
@abstractmethod
def write(self, data):
pass
-------------------------异步的例子:
import asyncio
async def slow_operator(n):
await asyncio.sleep(6)
print("slow operation {} complete".format(n))
async def main():
await asyncio.wait([
slow_operator(1),
slow_operator(2),
slow_operator(3)
])
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
或者:
tasks = [slow_operator(1),slow_operator(2),slow_operator(3)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
--------------------------------------
await 后面必须跟一个 awaitable 类型或者具有 __await__ 属性的对象. 要执行异步函数,应该用
asyncio 库中的事件循环机制来启动.
内置的装饰器比如 @staticmethod, @classmethod,@property 原理
也是一样的。例如,下面这两个代码片段是等价的:
class A:
@classmethod
def method(cls):
pass
class B:
# Equivalent definition of a class method
def method(cls):
pass
method = classmethod(method)
--------------------------
from urllib import request, parse
# Base URL being accessed
url = 'http://httpbin.org/get'
# Dictionary of query parameters (if any)
parms = {
'name1' : 'value1',
'name2' : 'value2'
}
# Encode the query string
querystring = parse.urlencode(parms)
# Make a GET request and read the response
u = request.urlopen(url+'?' + querystring)
resp = u.read()
-------
如果你需要使用 POST 方法在请求主体中发送查询参数,可以将参数编码后作为
可选参数提供给 urlopen() 函数,就像这样:
from urllib import request, parse
# Base URL being accessed
url = 'http://httpbin.org/post'
# Dictionary of query parameters (if any)
parms = {
'name1' : 'value1','name2' : 'value2'
}
# Encode the query string
querystring = parse.urlencode(parms)
# Make a POST request and read the response
u = request.urlopen(url, querystring.encode('ascii'))
resp = u.read()
--------------------------------
from urllib import request, parse
...
# Extra headers
headers = {
'User-agent' : 'none/ofyourbusiness',
'Spam' : 'Eggs'
}
req = request.Request(url, querystring.encode('ascii'), headers=headers)
# Make a request and read the response
u = request.urlopen(req)
resp = u.read()
----------------------------------
如果需要交互的服务比上面的例子都要复杂,也许应该去看看 requests 库(https:
//pypi.python.org/pypi/requests)。例如,下面这个示例采用 requests 库重新实现了上
面的操作:
import requests
# Base URL being accessed
url = 'http://httpbin.org/post'
# Dictionary of query parameters (if any)
parms = {
'name1' : 'value1',
'name2' : 'value2'
}
# Extra headers
headers = {
'User-agent' : 'none/ofyourbusiness',
'Spam' : 'Eggs'
}resp = requests.post(url, data=parms, headers=headers)
# Decoded text returned by the request
text = resp.text
-----------------------------
如果去访问 resp.content ,就会得到原始的二进制数据。另一方面,如果访问
resp.json ,那么就会得到 JSON 格式的响应内容。
----------------------------
import requests
resp = requests.head('http://www.python.org/index.html')
status = resp.status_code
last_modified = resp.headers['last-modified']
content_type = resp.headers['content-type']
content_length = resp.headers['content-length']
------------------
import requests
resp = requests.get('http://pypi.python.org/pypi?:action=login',
auth=('user','password'))
import requests
# First request
resp1 = requests.get(url)
...
# Second requests with cookies received on first requests
resp2 = requests.get(url, cookies=resp1.cookies)
-----------------------------
利用 requests 将 HTTP cookies 从一个请求传递到另一个的例子:
import requests
# First request
resp1 = requests.get(url)
...
# Second requests with cookies received on first requests
resp2 = requests.get(url, cookies=resp1.cookies)
最后但并非最不重要的一个例子是用 requests 上传内容:
import requests
url = 'http://httpbin.org/post'
files = { 'file': ('data.csv', open('data.csv', 'rb')) }
r = requests.post(url, files=files)
-------------------------------
创建一个 TCP 服务器的一个简单方法是使用 socketserver 库。例如,下面是一
个简单的应答服务器:
from socketserver import BaseRequestHandler, TCPServer
class EchoHandler(BaseRequestHandler):
def handle(self):
print('Got connection from', self.client_address)
while True:
msg = self.request.recv(8192)
if not msg:
break
self.request.send(msg)
if __name__ == '__main__':
serv = TCPServer(('', 20000), EchoHandler)
serv.serve_forever()
----------------------.
from socketserver import ThreadingTCPServer
if __name__ == '__main__':
serv = ThreadingTCPServer(('', 20000), EchoHandler)
serv.serve_forever()
---------------------------
如果你担心这个问题,你可以创建一个预先分配大小的工作线程池或进程池。你先
创建一个普通的非线程服务器,然后在一个线程池中使用 serve_forever() 方法来启
动它们。
if __name__ == '__main__':
from threading import Thread
NWORKERS = 16serv = TCPServer(('', 20000), EchoHandler)
for n in range(NWORKERS):
t = Thread(target=serv.serve_forever)
t.daemon = True
t.start()
serv.serve_forever()
------------------------------
查询线程运行状态:t.is_alive():
namedtuple 就加入到 Python 里, 用以
构建只有少数属性但是没有方法的对象, 比如数据库条目。spades(黑桃)
from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates') ?
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, position):#使其可迭代
return self._cards[position]
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
如果你只想实现这两个特殊方法中的一个, __repr__ 是更好的选择,
因为如果一个对象没有 __str__ 函数, 而 Python 又需要调用它的时
候, 解释器会用 __repr__ 作为替代。
扁平序列:list、 bytearray、 array.array、 collections.deque 和
memoryview。
>>> def simple_coroutine(): # ?
... print('-> coroutine started')
... x = yield # ?
... print('-> coroutine received:', x)
...
>>> my_coro = simple_coroutine()
>>> my_coro # ?
<generator object simple_coroutine at 0x100c2be10>
>>> next(my_coro) # ?
-> coroutine started
>>> my_coro.send(42) # ?
-> coroutine received: 42
Traceback (most recent call last): # ?
...
StopIteration
首先要调用 next(...) 函数, 因为生成器还没启动, 没在 yield 语
句处暂停, 所以一开始无法发送数据。
协程可以身处四个状态中的一个。 当前状态可以使用
inspect.getgeneratorstate(...) 函数确定, 该函数会返回下述字
符串中的一个。
'GEN_CREATED'
等待开始执行。
'GEN_RUNNING'
解释器正在执行。
只有在多线程应用中才能看到这个状态。 此外, 生成器对象在自己身上调用
getgeneratorstate 函数也行, 不过这样做没什么用。
'GEN_SUSPENDED'
在 yield 表达式处暂停。
'GEN_CLOSED'
执行结束。
因为 send 方法的参数会成为暂停的 yield 表达式的值, 所以, 仅当协
程处于暂停状态时才能调用 send 方法, 例如 my_coro.send(42)。 不
过, 如果协程还没激活(即, 状态是 'GEN_CREATED') , 情况就不同
了。 因此, 始终要调用 next(my_coro) 激活协程——也可以调用
my_coro.send(None), 效果一样。
关键的一点是, 协程在 yield 关键字所在的位置暂停执行。 前面说
过, 在赋值语句中, = 右边的代码在赋值之前执行。 因此, 对于 b =
yield a 这行代码来说, 等到客户端代码再激活协程时才会设定 b 的
值。 这种行为要花点时间才能习惯, 不过一定要理解,
从 Python 2.5 开始, 客户代码可以在生成器对象上调用两个方法, 显式
地把异常发给协程。这两个方法是 throw 和 close。
Python 3.3 引入 yield from 结构的主要原因之一与把异常传入嵌套的
协程有关。 另一个原因是让协程更方便地返回值.
yield from 可用于简化 for 循环中的 yield 表达式。
例如:
>>> def gen():
... for c in 'AB':
... yield c
... for i in range(1, 3):
... yield i
...
>>> list(gen())
['A', 'B', 1, 2]
可以改写为:
>>> def gen():
... yield from 'AB'
... yield from range(1, 3)
...
>>> list(gen())
['A', 'B', 1, 2]
yield from 的主要功能是打开双向通道, 把最外层的调用方与最内层
的子生成器连接起来, 这样二者可以直接发送和产出值, 还可以直接传
入异常, 而不用在位于中间的协程中添加大量处理异常的样板代码。 有
了这个结构, 协程可以通过以前不可能的方式委托职责。
线程池下载:
from concurrent import futures
from flags import save_flag, get_flag, show, main ➊//以前定义的下载函数
MAX_WORKERS = 20 ➋
def download_one(cc): ➌
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower() + '.gif')
return cc
def download_many(cc_list):
workers = min(MAX_WORKERS, len(cc_list)) ➍
with futures.ThreadPoolExecutor(workers) as executor: ➎
res = executor.map(download_one, sorted(cc_list)) ➏
return len(list(res)) ➐
if __name__ == '__main__':
main(download_many) ➑
-----------------------------------------
异步协程:
concurrent.futures.Future 和 asyncio.Future。 这两个类的作用相同: 两个 Future 类的实例都表
示可能已经完成或者尚未完成的延迟计算。 这与 Twisted 引擎中的 Deferred 类、 Tornado 框架中的
Future 类, 以及多个 JavaScript 库中的 Promise 对象类似。
def download_many(cc_list):
cc_list = cc_list[:5] ➊
with futures.ThreadPoolExecutor(max_workers=3) as executor: ➋
to_do = []
for cc in sorted(cc_list): ➌
future = executor.submit(download_one, cc) ➍
to_do.append(future) ➎
msg = 'Scheduled for {}: {}'
print(msg.format(cc, future)) ➏
results = []
for future in futures.as_completed(to_do): ➐
res = future.result() ➑
msg = '{} result: {!r}'
print(msg.format(future, res)) ➒
results.append(res)
return len(results)
-------------------------------------------------------------------------------------
w:字母,数字,下划线 word;
.除换行符以外的任意字符,如果允许匹配换行,也可以匹配换行符;
* 0次1,多次;
? 0到1次;
+ 1到多
[n] 前面的原子:恰好n次;[n,]至少N次; [n,m] 最少N次,最多M次;
模式修正:I 忽略大小写;M:多行:L本地化识别匹配;U:unicode解析
S:让.匹配换行;
re.compile(pat).findall(string) //查所有
urllib.request.urlretrieve('url','savepath')
urllib.request.urlcleanup()
file = urllib.request.urlopen(url,timeout=1)
file.info()
file.getcode()
file.geturl()
request.quote(urlencode)
urllib.parse.urlencode({"name":"coe","passwod":"xx"})
web开发的地方:
------------------------------------------------------------
RequestHandler.prepare(),RequestHandler.on_finish()
用于调用请求处理的之前的处理,一个是之后的清理;
Http Action在RequestHandler中可以单独处理:
RequestHandler.get,.head,.post,delete,patch,put,options.
输出捕获:RequestHandler.get_argument(name),RequestHandler.get_arguments(name)
.get_query_argument(),get_query_arguments(name)
get_cookie(name,default=None)
RequestHandler.request;//request.remote_ip,request.host
RequestHandler.set_status(status_code,reason=None)
RequestHandler.set_header(name,value)
.add_header(name,value)
.write(chunk)
.finish(chunk=None) 生成己完成;调用finish()后,tornado将向客户端发送HttpResoponse.本方法适合对RequestHandler的异步请求处理;同步不需要该方法;
转向:RequestHandler.redirect(url,permanent=False,status = None)
.clear()清空本次请求中之前写入的Header和Body内容;
RequestHandler.clear_all_cookies(path='/',domain=None)清空本次请求中所有的cookie;
get_current_user(self): 登录要实现的方法;
tornado变成了.current_user的属性;
pip install virtualenv
virtualenv venv
source ./venv/bin/active
deactivate
登陆:
由于异步,协程没有办法调用用户登录;所以
在prepare(self)中指定了,只要设置current_user 不为空,则不会调用配置中的login
登录方法:
1.在application中指定login_url='/login'
2.在@tornado.web.authenticated标记的方法中,要实现prepare方法,检测self.current_user不为空;为空则转/login;
#self.current_user = "admin"
3.在prepare中用
4.登陆用self.set_secure_cookie("blogdemo_user", str(author.id))
self.redirect(self.get_argument("next", "/"))
5.prepare中用if self.get_secure_cookie("blogdemo_user"),如果有设置;从数据库加载用户设置;
initialize(self,database)方法;RequestHandler.initialize() 初始化;
RequestHandler.current_user是一个只读属性,所以开发者需要重载RequestHandler.get_current_user()函数以设置该属性的值;
{% module xsrf_from_html() %}
------------
web socket 请求头:
1. Connection:Upgrade
2. Sec-WebSocket-Key: uR.....
3. Upgrade:websocket
4. Sec-WebSocket-Version:13
服务器返回:
1.Connection:Upgrade
2.Upgrade: WebSocket
3.Sec-WebSocket-Accept:rH.....key...
tornado.websocket.WebSocketHandler类用于处理WebSocket链接请求;开发者应该继承实现open(),on_message(),on_close()函数:
open():链接建立,on_message()收到客户端消息时调用;on_close()通过self.close_code和self.close_reason查询关闭的原因;
.write_message()向客户端写;
.close()主动关闭链接;
模板中可以import函数;
{% import time %}
{{ time.time() }}
UI模块是从模板向后台调用,在前台模板中重复调用的,需要反复渲染的,class EntryModule(tornado.web.UIModule):
def render(self, entry):
return self.render_string("modules/entry.html", entry=entry)
前台:{% for entry in entries %}
{% module Entry(entry) %}
{% end %} index中的entry作为参数,传到后台了。而后台则是作为参数,再进一步传给ui渲染;