常用模块

文件操作##

读取文件

  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,便可以了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容