文件操作##
读取文件
try:
f = open("test.txt", "r")
print f.read()
finally:
if f: f.close()
可以使用with块缩短代码
with open("test.txt", "r") as f:
print f.read()
分块读取
f.read(size)
按行读取:如果要一次性读取所有行,只需调用readlines()
f.readline() # 按行读取, 如果要一次性读取所有行,只需调用readlines()
open("test.txt", "rb") # 读取二进制文件
读取非ASC2编码的文件:两种方式
第一种方式:用二进制读取之后再转码
第二种方式:用第三个参数指定编码
open("test.txt", "r", "utf8")
写文件:跟读文件一样
对象序列化##
python的原版对象不能进行序列化,必须转成Dict才可以。
cPickle和pickle:cPickle支持中文,能用就用
d = { "name": "opower", "age": 18 }
print pickle.dump(d)
with open("test.txt", "r") as f:
pickle.dump(d, f)
print pickle.load(f) # 反序列化
JSON:pickle是针对python的,通用的方法是转成JSON格式
# 序列化和反序列化跟pickle是一样的(就是函数名后面多了个s)
# 关键在于json的dump提供一个转化函数的参数,可以把一般对象转成Dict后再序列化
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
print(json.dumps(s, default=student2dict))
# 因为通常class的实例都有一个__dict__属性,它就是一个dict,
# 用来存储实例变量。也有少数例外,比如定义了__slots__的class。
print(json.dumps(s, default=lambda obj: obj.__dict__))
# 反序列一样也可以
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook=dict2student))
多进程##
Linux和Unix的系统,有自带的fork系统函数可以生成进程
# getpid:获取当前进程的ID
# getppid:获取父进程的ID
import os
print 'Process (%s) start...' % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
如果是window平台,需要用multiprocessing模块的Process类
# 如果是window平台,需要用multiprocessing模块的Process类
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print 'Run child process %s (%s)...' % (name, os.getpid())
if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
p = Process(target=run_proc, args=('test',))
print 'Process will start.'
p.start()
p.join()
print 'Process end.'
- 可以看出Process接受两个参数,第一个是进程的入口函数;第二个是传入的参数
- join()函数意味着当前进程会停下来,等待子进程执行结束之后再执行
- Process实际上比fork好用,multiprocessing库封装了fork
进程池:可以从进程池批量管理进程池
from multiprocessing import Pool
import os
def printInfo(idx):
print "Index is",idx,", pid is",os.getpid()
if __name__=='__main__':
p = Pool()
for i in range(5):
p. apply_async(printInfo, args=(i,))
p.close()
p.join()
close - 表示进程池不再接受进程(我的理解是所有进程池的进程start,所以join函数得在close之后执行)
进程间通讯:Queue列队和Pipes通道,详细看例子吧
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print 'Put %s to queue...' % value
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
value = q.get(True)
print 'Get %s from queue.' % value
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
多线程##
利用线程的高级模块,创建线程和进程一样很简单
import threading, time, random
def printInfo():
for i in range(5):
time.sleep(random.random() * 3)
print "Hello",i
if __name__=='__main__':
thd = threading.Thread(target=printInfo)
thd.start()
thd.join()
print "Sub thread ended"
线程锁:多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。(选自廖雪峰python教程)
import threading, time, random
store = 20
lock = threading.Lock()
def sell(name):
global store
while store > 0:
lock.acquire() # 加锁
store -= 1
print "use by",name,"current:",store
lock.release() # 解锁
if __name__=='__main__':
thdSell1 = threading.Thread(target=sell, args=("sell1",))
thdSell2 = threading.Thread(target=sell, args=("sell2",))
thdSell1.start()
thdSell2.start()
thdSell1.join()
thdSell2.join()
print "Application ended"
- 可以尝试着把加锁/解锁代码注释掉,查看结果
- 如果最后看到负数输出,考虑是因为什么原因,怎么检查原因,最后应该怎么解决
线程局部变量:每个线程有自己需要维护的一组局部变量,如果线程有多个函数,要使用某个局部变量只能依靠参数传递,为了防止函数参数表爆表,py提供了Threading.local
import threading
local_child = threading.local()
lock = threading.Lock()
def giveFruit(fruit):
lock.acquire()
local_child.fruit = fruit
print getInfo()
lock.release()
def getInfo():
return local_child.fruit
if __name__=='__main__':
thdSell1 = threading.Thread(target=giveFruit, args=("apple",))
thdSell2 = threading.Thread(target=giveFruit, args=("orange",))
thdSell1.start()
thdSell2.start()
thdSell1.join()
thdSell2.join()
print "Application ended"
python属于语法相对简单的脚本语言,比起C等传统高级语言,优势在于开发迅捷。因此适用于性能要求不太高的场合,而这样的场合经常出现在普通IO操作上,因此,网络应用、大数据量的输入输入很适合py。但对计算效率要求高的应用(解码、加压解压、跑算法等),如果效果不佳,还是尝试用传统高级语言。
上面线程锁最后输出负数的例子,可以尝试在循环头部打印一下当前执行的线程是哪个
...
while store > 0:
print "This is",name
lock.acquire() # 加锁
...
我们会看下输出结果是:
This is sell1
use by sell2 current: 8
This is sell2
use by sell2 current: 7
This is sell2
use by sell2 current: 6
This is sell2
use by sell2 current: 5
This is sell2
use by sell2 current: 4
This is sell2
use by sell2 current: 3
This is sell2
use by sell2 current: 2
This is sell2
use by sell2 current: 1
This is sell2
use by sell1 current: 0
use by sell2 current: -1
可以看到,当库存还有9的时候,线程1进入循环,但紧接着被线程2打断。线程2一直执行到库存还有1的时候,也是进入循环之后被线程1打断,线程1用掉最后一个库存,但不要忘了,这个时候2已经进入循环了,于是它在0库存的基础上用了不存在的值。
修正的方法也很简单,做一个死循环,所有的逻辑都放在里面并被锁包住,跳出条件是库存小于等于0,便可以了。