Python3学习笔记12-标准库之多进程、数学、循环器、数据库sqLite

1、多进程探索 (multiprocessing包)

上一节的最后,初步了解Python多进程,如今咱们能够继续探索multiprocessing包中更加高级的工具。这些工具可让咱们更加便利地实现多进程。html

一、进程池

**进程池 (Process Pool)**能够建立多个进程。这些进程就像是随时待命的士兵,准备执行任务(程序)。一个进程池中能够容纳多个待命的士兵: 输入图片说明python

好比下面的程序:算法

import multiprocessing as mul

def f(x):
    return x**2

pool = mul.Pool(5)
rel  = pool.map(f,[1,2,3,4,5,6,7,8,9,10])
print(rel)

#打印结果:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

咱们建立了一个允许5个进程的进程池 (Process Pool) 。Pool运行的每一个进程都执行f()函数。咱们利用map()方法,将f()函数做用到表的每一个元素上。这与built-in的map()函数相似,只是这里用5个进程并行处理。若是进程运行结束后,还有须要处理的元素,那么的进程会被用于从新运行f()函数。除了map()方法外,Pool还有下面的经常使用方法。sql

apply_async(func,args) 从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你能够对该对象调用**get()**方法以得到结果。数据库

close() 进程池再也不建立新的进程编程

join() wait进程池中的所有进程。必须对Pool先调用close()方法才能join后端

###二、共享资源 咱们在Python多进程初步已经提到,咱们应该尽可能避免多进程共享资源。多进程共享资源必然会带来进程间相互竞争。而这种竞争又会形成race condition,咱们的结果有可能被竞争的不肯定性所影响。但若是须要,咱们依然能够经过共享内存和Manager对象这么作。数组

输入图片说明

共享内存安全

咱们已经讲述了**共享内存(shared memory)**的原理,这里给出用Python实现的例子:服务器

# modified from official documentation
import multiprocessing

def f(n, a):
    n.value   = 3.14
    a[0]      = 5

num   = multiprocessing.Value('d', 0.0)
arr   = multiprocessing.Array('i', range(10))

p = multiprocessing.Process(target=f, args=(num, arr))
p.start()
p.join()

print num.value   # 打印结果:3.14
print arr[:]       # 打印结果:5, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这里咱们实际上只有主进程和Process对象表明的进程。咱们在主进程的内存空间中建立共享的内存,也就是Value和Array两个对象。对象Value被设置成为双精度数(d), 并初始化为0.0。而Array则相似于C中的数组,有固定的类型(i, 也就是整数)。在Process进程中,咱们修改了Value和Array对象。回到主程序,打印出结果,主程序也看到了两个对象的改变,说明资源确实在两个进程之间共享。

Manager

Manager对象相似于服务器与客户之间的通讯 (server-client),与咱们在Internet上的活动很相似。咱们用一个进程做为服务器,创建Manager来真正存放资源。其它的进程能够经过参数传递或者根据地址来访问Manager,创建链接后,操做服务器上的资源。在防火墙容许的状况下,咱们彻底能够将Manager运用于多计算机,从而模仿了一个真实的网络情境。下面的例子中,咱们对Manager的使用相似于shared memory,但能够共享更丰富的对象类型。

import multiprocessing

def f(x, arr, l):
    x.value = 3.14
    arr[0] = 5
    l.append('Hello')

server = multiprocessing.Manager()
x    = server.Value('d', 0.0)
arr  = server.Array('i', range(10))
l    = server.list()

proc = multiprocessing.Process(target=f, args=(x, arr, l))
proc.start()
proc.join()

print(x.value)
print(arr)
print(l)

Manager利用list()方法提供了表的共享方式。实际上你能够利用dict()来共享词典,Lock()来共享threading.Lock(注意,咱们共享的是threading.Lock,而不是进程的mutiprocessing.Lock。后者自己已经实现了进程共享)等。 这样Manager就容许咱们共享更多样的对象。

##2、数学与随机数 (math包,random包) 咱们已经在Python运算中看到Python最基本的数学运算功能。此外,math包补充了更多的函数。固然,若是想要更加高级的数学功能,能够考虑选择标准库以外的numpyscipy项目,它们不但支持数组和矩阵运算,还有丰富的数学和物理方程可供使用,牛逼啊

此外,random包能够用来生成随机数。随机数不只能够用于数学用途,还常常被嵌入到算法中,用以提升算法效率,并提升程序的安全性。

###一、math包 math包主要处理数学相关的运算。math包定义了两个常数:

math.e   # 天然常数e
math.pi  # 圆周率pi
此外,math包还有各类运算函数 (下面函数的功能能够参考数学手册):

math.ceil(x)       # 对x向上取整,好比x=1.2,返回2
math.floor(x)      # 对x向下取整,好比x=1.2,返回1
math.pow(x,y)      # 指数运算,获得x的y次方
math.log(x)        # 对数,默认基底为e。可使用base参数,来改变对数的基地。好比math.log(100,base=10)
math.sqrt(x)       # 平方根

三角函数: math.sin(x), math.cos(x), math.tan(x), math.asin(x), math.acos(x), math.atan(x)

这些函数都接收一个弧度(radian)为单位的x做为参数。

角度和弧度互换: math.degrees(x), math.radians(x)

双曲函数: math.sinh(x), math.cosh(x), math.tanh(x), math.asinh(x), math.acosh(x), math.atanh(x)

特殊函数: math.erf(x), math.gamma(x)

###二、random包 若是你已经了解**伪随机数(psudo-random number)**的原理,那么你可使用以下:

random.seed(x)

来改变随机数生成器的种子seed。若是你不了解其原理,你没必要特别去设定seed,Python会帮你选择seed。

####(1)、随机挑选和排序

random.choice(seq)   # 从序列的元素中随机挑选一个元素,好比random.choice(range(10)),从0到9中随机挑选一个整数。
random.sample(seq,k) # 从序列中随机挑选k个元素
random.shuffle(seq)  # 将序列的全部元素随机排序

####(2)、随机生成实数

下面生成的实数符合均匀分布(uniform distribution),意味着某个范围内的每一个数字出现的几率相等:

random.random()          # 随机生成下一个实数,它在[0,1)范围内。
random.uniform(a,b)      # 随机生成下一个实数,它在[a,b]范围内。

下面生成的实数符合其它的分布 (你能够参考一些统计方面的书籍来了解这些分布):

random.gauss(mu,sigma)    # 随机生成符合高斯分布的随机数,mu,sigma为高斯分布的两个参数。 
random.expovariate(lambd) # 随机生成符合指数分布的随机数,lambd为指数分布的参数。

此外还有对数分布,正态分布,Pareto分布,Weibull分布,可参考下面连接:

http://docs.python.org/library/random.html

假设咱们有一群人参加舞蹈比赛,为了公平起见,咱们要随机排列他们的出场顺序。咱们下面利用random包实现:

import random
all_people = ['Tom', 'Vivian', 'Paul', 'Liya', 'Manu', 'Daniel', 'Shawn']
random.shuffle(all_people)
for i,name in enumerate(all_people):
    print(i,':'+name)

##3、循环器 (itertools) 在循环对象和函数对象中,咱们了解了循环器(iterator)的功能。循环器是对象的容器,包含有多个对象。经过调用循环器的next()方法 (next()方法,在Python 3.x中),循环器将依次返回一个对象。直到全部的对象遍历穷尽,循环器将举出StopIteration错误。

itertools的工具均可以自行实现。itertools只是提供了更加成形的解决方案。

在for i in iterator结构中,循环器每次返回的对象将赋予给i,直到循环结束。使用**iter()**内置函数,咱们能够将诸如表、字典等容器变为循环器。好比:

for i in iter([2, 4, 5, 6]):
    print(i)

标准库中的itertools包提供了更加灵活的生成循环器的工具。这些工具的输入大都是已有的循环器。另外一方面,这些工具彻底能够自行使用Python实现,该包只是提供了一种比较标准、高效的实现方式。这也符合Python“只有且最好只有解决方案”的理念。

# import the tools
from itertools import *

###一、无穷循环器

count(5, 2)     #从5开始的整数循环器,每次增长2,即5, 7, 9, 11, 13, 15 ...
cycle('abc')    #重复序列的元素,既a, b, c, a, b, c ...
repeat(1.2)     #重复1.2,构成无穷循环器,即1.2, 1.2, 1.2, ...

repeat也能够有一个次数限制:

repeat(10, 5)   #重复10,共重复5次

###二、函数式工具 函数式编程是将函数自己做为处理对象的编程范式。在Python中,函数也是对象,所以能够轻松的进行一些函数式的处理,好比map(), filter(), reduce()函数

itertools包含相似的工具。这些函数接收函数做为参数,并将结果返回为一个循环器

好比:

from itertools import *

rlt = imap(pow, [1, 2, 3], [1, 2, 3])

for num in rlt:
    print(num)

上面显示了imap函数。该函数与map()函数功能类似,只不过返回的不是序列,而是一个循环器。包含元素1, 4, 27,即11, 22, 33的结果。函数pow**(内置的乘方函数)做为第一个参数。pow()依次做用于后面两个列表的每一个元素,并收集函数结果,组成返回的循环器。

此外,还能够用下面的函数:

starmap(pow, [(1, 1), (2, 2), (3, 3)])     #pow将依次做用于表的每一个tuple。
ifilter函数与filter()函数相似,只是返回的是一个循环器。

ifilter(lambda x: x > 5, [2, 3, 5, 6, 7]) #将lambda函数依次做用于每一个元素,若是函数返回True,则收集原来的元素。6, 7。

此外:

ifilterfalse(lambda x: x > 5, [2, 3, 5, 6, 7])     #与上面相似,但收集返回False的元素。2, 3, 5
takewhile(lambda x: x < 5, [1, 3, 6, 7, 1])     #当函数返回True时,收集元素到循环器。一旦函数返回False,则中止。1, 3
dropwhile(lambda x: x < 5, [1, 3, 6, 7, 1])     #当函数返回False时,跳过元素。一旦函数返回True,则开始收集剩下的全部元素到循环器。6, 7, 1

###三、组合工具 咱们能够经过组合原有循环器,来得到新的循环器。

chain([1, 2, 3], [4, 5, 7])      # 链接两个循环器成为一个。1, 2, 3, 4, 5, 7
product('abc', [1, 2])   # 多个循环器集合的笛卡尔积。至关于嵌套循环
for m, n in product('abc', [1, 2]):
    print m, n
permutations('abc', 2)   # 从'abc'中挑选两个元素,好比ab, bc, ... 将全部结果排序,返回为新的循环器。

注意,上面的组合分顺序,即ab, ba都返回。

combinations('abc', 2)   # 从'abcd'中挑选两个元素,好比ab, bc, ... 将全部结果排序,返回为新的循环器。

注意,上面的组合不分顺序,即ab, ba的话,只返回一个ab。

combinations_with_replacement('abc', 2) # 与上面相似,但容许两次选出的元素重复。即多了aa, bb, cc

###四、groupby() 将key函数做用于原循环器的各个元素。根据key函数结果,将拥有相同函数结果的元素分到一个新的循环器。每一个新的循环器以函数返回结果为标签。

这就好像一群人的身高做为循环器。咱们可使用这样一个key函数: 若是身高大于180,返回"tall";若是身高底于160,返回"short";中间的返回"middle"。最终,全部身高将分为三个循环器,即"tall", "short", "middle"。

def height_class(h):
    if h > 180:
        return "tall"
    elif h < 160:
        return "short"
    else:
        return "middle"

friends = [191, 158, 159, 165, 170, 177, 181, 182, 190]

friends = sorted(friends, key = height_class)
for m, n in groupby(friends, key = height_class):
    print(m)
    print(list(n))

注意,groupby的功能相似于UNIX中的uniq命令。分组以前须要使用sorted()对原循环器的元素,根据key函数进行排序,让同组元素先在位置上靠拢

###五、其它工具

compress('ABCD', [1, 1, 1, 0])  # 根据[1, 1, 1, 0]的真假值状况,选择第一个参数'ABCD'中的元素。A, B, C
islice()                        # 相似于slice()函数,只是返回的是一个循环器
izip()                          # 相似于zip()函数,只是返回的是一个循环器。

##4、数据库 (sqlite3) Python自带一个轻量级的关系型数据库SQLite。这一数据库使用SQL语言。SQLite做为后端数据库,能够搭配Python建网站,或者制做有数据存储需求的工具。SQLite还在其它领域有普遍的应用,好比HTML5和移动端。Python标准库中的sqlite3提供该数据库的接口。

我将建立一个简单的关系型数据库,为一个书店存储书的分类和价格。数据库中包含两个表:category用于记录分类,book用于记录某个书的信息。一本书归属于某一个分类,所以book有一个外键(foreign key),指向catogory表的主键id。

输入图片说明

sqlite3只是一个SQLite的接口。想要熟练的使用SQLite数据库,还须要学习更多的关系型数据库的知识。

###一、建立数据库 我首先来建立数据库,以及数据库中的表。在使用connect()链接数据库后,我就能够经过定位指针cursor,来执行SQL命令:

import sqlite3

# test.db is a file in the working directory.
conn = sqlite3.connect("test.db")

c = conn.cursor()

# create tables
c.execute('''CREATE TABLE category
      (id int primary key, sort int, name text)''')
c.execute('''CREATE TABLE book
      (id int primary key, 
       sort int, 
       name text, 
       price real, 
       category int,
       FOREIGN KEY (category) REFERENCES category(id))''')

# save the changes
conn.commit()

# close the connection with the database
conn.close()

SQLite的数据库是一个磁盘上的文件,如上面的test.db,所以整个数据库能够方便的移动或复制。test.db一开始不存在,因此SQLite将自动建立一个新文件

利用execute()命令,我执行了两个SQL命令,建立数据库中的两个表。建立完成后,保存并断开数据库链接。

###二、插入数据 上面建立了数据库和表,确立了数据库的抽象结构。下面将在同一数据库中插入数据:

import sqlite3

conn = sqlite3.connect("test.db")
c    = conn.cursor()

books = [(1, 1, 'Cook Recipe', 3.12, 1),
            (2, 3, 'Python Intro', 17.5, 2),
            (3, 2, 'OS Intro', 13.6, 2),
           ]

# execute "INSERT" 
c.execute("INSERT INTO category VALUES (1, 1, 'kitchen')")

# using the placeholder
c.execute("INSERT INTO category VALUES (?, ?, ?)", [(2, 2, 'computer')])

# execute multiple commands
c.executemany('INSERT INTO book VALUES (?, ?, ?, ?, ?)', books)

conn.commit()
conn.close()

插入数据一样可使用execute()来执行完整的SQL语句。SQL语句中的参数,使用"?"做为替代符号,并在后面的参数中给出具体值。这里不能用Python的格式化字符串,如"%s",由于这一用法容易受到SQL注入攻击

我也能够用**executemany()**的方法来执行屡次插入,增长多个记录。每一个记录是表中的一个元素,如上面的books表中的元素。

###三、查询 在执行查询语句后,Python将返回一个循环器,包含有查询得到的多个记录。你循环读取,也可使用sqlite3提供的**fetchone()和fetchall()**方法读取记录:

import sqlite3

conn = sqlite3.connect('test.db')
c = conn.cursor()

# retrieve one record
c.execute('SELECT name FROM category ORDER BY sort')
print(c.fetchone())
print(c.fetchone())

# retrieve all records as a list
c.execute('SELECT * FROM book WHERE book.category=1')
print(c.fetchall())

# iterate through the records
for row in c.execute('SELECT name, price FROM book ORDER BY sort'):
    print(row)

查询结果:

c.execute('SELECT * FROM book ORDER BY sort')
print(c.fetchall())

输入图片说明

###四、更新与删除 你能够更新某个记录,或者删除记录:

conn = sqlite3.connect("test.db")
c = conn.cursor()

c.execute('UPDATE book SET price=? WHERE id=?',(1000, 1))
c.execute('DELETE FROM book WHERE id=2')

conn.commit()
conn.close()

你也能够直接删除整张表:

c.execute('DROP TABLE book')

若是删除test.db,那么整个数据库会被删除。

注:本Python学习笔记是按照Vamei的博客教程来学习的,若有兴趣能够参考Vamei Python快速开发博文

相关文章
相关标签/搜索