该博客用于记录自己在学习Python中遇到的各种问题和解决方法,不定时更新
2017年5月24日
sort和sorted
Python中的sort和sorted方法用于数组排序:
-sorted(iterable, cmp=None, key=None, reverse=False) –> new sorted list
-L.sort(cmp=None, key=None, reverse=False) – stable sort IN PLACE;
iterable:是可迭代类型;
cmp:用于比较的函数,比较什么由key决定,有默认值,迭代集合中的一项;
key:用列表元素的某个属性和函数进行作为关键字,有默认值,迭代集合中的一项;
reverse:排序规则. reverse = True 或者 reverse = False,有默认值。
返回值:是一个经过排序的可迭代类型,与iterable一样。
注:一般来说,cmp和key可以使用lambda表达式。
sort()与sorted()的不同在于,sort是在原位重新排列列表,而sorted()是产生一个新的列表。
如果排序内容为中文,则默认按照中文编码进行排序(Python3默认为utf-8)
list = ["果汁","啤酒","饮料","菠萝","苹果"]
list.sort()
print(list)#['啤酒', '果汁', '苹果', '菠萝', '饮料']
果汁 果汁
啤酒 啤酒
饮料 饮料
菠萝 菠萝
苹果 苹果
#基本用法
x = [4, 6, 2, 1, 7, 9]
x.sort()
print (x) # [1, 2, 4, 6, 7, 9]
print (sorted('Python')) #['P', 'h', 'n', 'o', 't', 'y']
#自定义比较函数
def comp(x, y):
if x < y:
return
1elif x > y:
return -1
else:
return 0
nums = [3, 2, 8 ,0 , 1]
nums.sort(comp)
print (nums) # 降序排序[8, 3, 2, 1, 0]
nums.sort(cmp) # 调用内建函数cmp ,升序排序print nums # 降序排序[0, 1, 2, 3, 8]
#可选函数
x = ['mmm', 'mm', 'mm', 'm' ]
x.sort(key = len)
print (x) # ['m', 'mm', 'mm', 'mmm']
y = [3, 2, 8 ,0 , 1]
y.sort(reverse = True)
print (y) #[8, 3, 2, 1, 0]
2017年5月25日
正则匹配
匹配的基本模式:
• 普通的文本值代表自身,用于匹配非特殊字符;
• 使用 . 代表任意除 \n 外的字符;
• 使用 * 表示任意多个字符(包括 0 个);
• 使用 ? 表示可选字符(0 个或 1 个)。
特殊字符:
\d 一个数字字符
\D 一个非数字字符
\w 一个字母或数字字符
\W 一个非字母非数字字符
\s 空白符
\S 非空白符
\b 单词边界(一个 \w 与 \W 之间的范围,顺序可逆)
\B 非单词边界
测试:
Python 的 string 模块中预先定义了一些可供我们测试用的字符串常量,这里使用 printable 字符串,它包含 100 个可打印的 ASCII 字符,包括大小写字母、数字、空格符以及标点符号:
import string
import re
printable = string.printable
print(len(printable))
# 100
print(printable[0:50])
# 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN
print(printable[50:])
# OPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
#上面的数据串包括各种空格符
print(re.findall('\d', printable))
# ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
print(re.findall('\w', printable))
# 显示出所有数字和大小写字母
print(re.findall('\s', printable))
# [' ', '\t', '\n', '\r', '\x0b', '\x0c']
使用标识符
下表中,expr 和其他斜体的单词表示合法的正则表达式。
abc 文本值 abc
( expr) expr
expr1 | expr2 expr1或 expr2
. 除 \n 外的任何字符
^ 源字符串的开头
$ 源字符串的结尾
prev ? 0 个或 1 个 prev
prev * 0 个或多个 prev,尽可能多地匹配
prev *? 0 个或多个 prev,尽可能少地匹配
prev + 1 个或多个 prev,尽可能多地匹配
prev +? 1 个或多个 prev,尽可能少地匹配
prev {m} m 个连续的 prev
prev {m, n} m 到 n 个连续的 prev,尽可能多地匹配
prev {m, n}? m 到 n 个连续的 prev,尽可能少地匹配
[abc] a 或 b 或 c (和 a|b|c 一样)
[^abc] 非( a 或 b 或 c )
prev ( ?= next) 如果后面为 next,返回 prev
prev ( ?! next) 如果后面非 next,返回 prev
( ?<= prev) next 如果前面为 prev,返回 next
( ?<!prev) next 如果前面非 prev,返回 next
source = ‘I wish I may, I wish I might have a dish of fish tonight.’
在源字符串中检索 wish :
re.findall(‘wish’, source)
对源字符串任意位置查询 wish 或者 fish :
re.findall(‘wish|fish’, source)
从字符串开头开始匹配 wish :
re.findall(‘^wish’, source)
从字符串开头开始匹配 I wish :
re.findall(‘^I wish’, source)
从字符串结尾开始匹配 fish :
re.findall(‘fish$’, source)
从字符串结尾开始匹配 fish tonight. :
re.findall(‘fish tonight.$’, source)
^ 和 $ 叫作锚点(anchor): ^ 将搜索域定位到源字符串的开头, $ 则定位到末尾。上面例子中的 .$ 可以匹配末尾的任意字符,包括句号,因此能成功匹配。但更准确地说,上面的例子应该使用转义符将 . 转义为句号,这才是我们真正想示意的纯文本值匹配:
re.findall(‘fish tonight.$’, source)
接下来查询以 w 或 f 开头,后面紧接着 ish 的匹配:
re.findall(‘[wf]ish’, source)
查询以若干个 w 、 s 或 h 组合的匹配:
re.findall(‘[wsh]+’, source)
查询以 ght 开头,后面紧跟一个非数字非字母字符的匹配:
re.findall(‘ght\W’, source)
查询以 I 开头,后面跟着 wish 的匹配( wish 出现次数尽量少):
re.findall(‘I (?=wish)’, source)
最后查询以 wish 结尾,前面为 I 的匹配( I 出现的次数尽量少):
re.findall(‘(?<=I) wish’, source)
在任何使用正则表达式的地方都记着在模式串的前面添加字符 r ,这样
可以告诉 Python 这是一个正则表达式,从而禁用字符串转义符。
#re.findall(‘\bfish’, source)
#上面的语句错误,因为\b在Python语法中是退格,但是在正则匹配中代表一个单词的开头
re.findall(r’\bfish’, source)
定义匹配的输出
当使用 match() 或 search() 时,所有的匹配会以 m.group() 的形式返回到对象 m 中。如果你用括号将某一模式包裹起来,括号中模式匹配得到的结果归入自己的 group (无名称)中,而调用 m.groups() 可以得到包含这些匹配的元组。
(?P< name >expr) 这样的模式会匹配 expr ,并将匹配结果存储到名为 name 的组中:
source = 'I wish I may, I wish I might have a dish of fish tonight.'
m = re.search(r'(. dish\b).*(\bfish)', source)
m.group()
#'a dish of fish'
m.groups()
#('a dish', 'fish')
m = re.search(r'(?P<DISH>. dish\b).*(?P<FISH>\bfish)', source)
m.group()
#'a dish of fish'
m.groups()
#('a dish', 'fish')
m.group('DISH')
'a dish'
m.group('FISH')
'fish'
2017年5月29日
并发与网络
关于并发
在计算机中,如果你的程序在等待,通常是因为以下两个原因。
• I/O 限制
这个限制很常见。计算机的 CPU 速度非常快——比计算机内存快几百倍,比硬盘或者网络快几千倍。
• CPU 限制
在处理数字运算任务时,比如科学计算或者图形计算,很容易遇到这个限制。
使用队列可以让程序多个进程并发的执行:
1. 进程
对单机来说,标准库中的 multiprocessing 模块有一个 Queue 函数。
2. 线程
线程运行在进程内部,可以访问进程的所有内容. multiprocessing 模块有一个兄弟模块 threading ,后者用线程来代替进程(实际上, multiprocessing 是在threading 之后设计出来的,基于进程来完成各种任务)。
建议
• 使用线程来解决 I/O 限制问题;
• 使用进程、网络或者事件来处理 CPU 限制问题。
3. 绿色线程和 gevent(http://www.gevent.org/)
基于事件的程序会运行一个核心事件循环,分配所有任务,然后重复这个循环。
gevent 就是一个基于事件的很棒的库,可以修改
许多 Python 的标准对象,比如 socket ,从而使用它自己的机制来代替阻塞。协程无法处理 C 写成的 Python 扩展代码,比如一些数据库驱动程序。
(Python2)
4. twisted
twisted (http://twistedmatrix.com/trac/)是一个异步事件驱动的网络框架。你可以把函数关
联到事件(比如数据接收或者连接关闭)上,当事件发生时这些函数会被调用。
(Python2)
5. asyncio
(http://legacy.python.org/dev/peps/pep-3156/)
asyncio 模块在 Python 3.4 中首次出现。
目前,它提供了一种通用的事件循环,可以兼容 twisted 、 gevent 和其他异步方法。
6. Redis(http://redis.io/)
Redis既支持单机又支持网络
可以使用 Redis 列表来快速创建一个队列。Redis 服务器部署在一台机器上;客户端可以部署在同一台机器上也可以部署在不同机器上,通过网络通信。无论是哪种情况,客户端都是通过使用 TCP 和服务器通信,因此它们是网络化的。一个或多个生产者客户端向列表的一端压入消息,一个或多个工人客户端通过阻塞弹出操作从列表中获得需要洗的盘子。如果列表为空,它们就会闲置。如果有一条消息,第一个空闲工人就会去处理。
7. 队列之上
• celery (http://www.celeryproject.org/)
这个包非常值得一看。它可以同步或者异步执行分布式任务,使用了我们之前介绍的方法: multiprocessing 、 gevent 等。
• thoonk
(https://github.com/andyet/thoonk.py)
这个包基于 Redis 构建,可以创建任务队列并实现发布 - 订阅(下一节会介绍)。
• rq(http://python-rq.org/)
这是一个处理任务队列的 Python 库,同样基于 Redis。
• Queues(http://queues.io/)
这个网站介绍了队列化软件,其中有些是基于 Python 开发的。
关于网络
(跨空间的分布式计算)
模式:
你可以使用一些基础的模式来搭建网络化应用。
最常见的模式是请求 - 响应,也被称为客户端 - 服务器。这个模式是同步的:用户会一直等待服务器的响应。你的 Web 浏览器也是一个客户端,向 Web 服务器发起一个 HTTP 请求并等待响应。
另一种常见的模式是推送或者扇出:你把数据发送到一个进程池中,空闲的工作进程会进行处理。一个典型的例子是有负载均衡的 Web 服务器。
和推送相反的是拉取或者扇入:你从一个或多个源接收数据。一个典型的例子是记录器,它会从多个进程接收文本信息并把它们写入一个日志文件。
还有一个和收音机或者电视广播很像的模式:发布 - 订阅。这个模式中,会有发送数据的发布者。在简单的发布 - 订阅系统中,所有的订阅者都会收到一份副本。更常见的情况是,订阅者只关心特定类型的数据(通常被称为话题),发布者只会发送这些数据。因此,和推送模式不同,可能会有超过一个订阅者收到数据。如果一个话题没有订阅者,相关的数据会被忽略。
• UDP 可以发送消息,但是消息的大小有限制,而且不能保证消息到达目的地。
• TCP 发送字节流,不是消息。你不知道每次调用时系统会发送或者接收多少字节。
• ZeroMQ(http://zguide.zeromq.org/)实现了许多普通他芥子没有的功能:1.传输完整的消息 2.重连 3.当发送方和接收方的时间不同步时缓存数据