Python 进阶
使用 Python2 or 3 的过程中遇到的一些 trick。
报错解决
socket 端口占用问题
正常退出程序后,再次启动也会报错:socket.error: [Errno 48] Address already in use
。原因是先前的执行使套接字处于 TIME_WAIT
状态,并且无法立即重用。SO_REUSEADDR
标志告诉内核在 TIME_WAIT
状态下重用本地套接字,而不等待其自然超时到期。
添加参数:
1
2
3
4from socket import *
sock=socket()
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
安装 gmpy2 的时候报错
src/gmpy.h:106:19: 致命错误:gmp.h:没有那个文件或目录
> 安装gmp
:- 在 debian、ubuntu 上使用命令:
sudo apt-get install libgmp-dev
- 在 Fedora、RedHat、CentOS 上使用命令:
sudo yum install gmp-devel
- 在 debian、ubuntu 上使用命令:
src/gmpy.h:252:20: 致命错误:mpfr.h:没有那个文件或目录
> 下载MPFR
:https://www.mpfr.org/mpfr-current/#download
。示例:
1
2
3
4
5
6wget https://www.mpfr.org/mpfr-current/mpfr-4.0.1.tar.xz
tar -xf mpfr-4.0.1.tar.xz
cd mpfr-4.0.1
./configure
make
make installsrc/gmpy.h:261:19: 致命错误:mpc.h:没有那个文件或目录
> 安装gmp
:- 在 debian、ubuntu 上使用命令:
sudo apt-get install libmpc-dev
- 在 Fedora、RedHat、CentOS 上使用命令:
sudo yum install libmpc-devel
- 在 debian、ubuntu 上使用命令:
知识与技巧
充当连接符的“空格字符”
1 |
|
这里的充当,有时候会造成奇怪的 bug:
1
2
3
4
5
6
7In [2]: info = "This is a test."
In [3]: any(discard in info for discard in [
...: "overflow", "Overflow"
...: "test", "null",
...: "DLL",
...: ])
Out[3]: False
1
2
3
4
5
6
7In [2]: info = "This is a test."
In [3]: any(discard in info for discard in [
...: "overflow", "Overflow",
...: "test", "null",
...: "DLL",
...: ])
Out[3]: True
捕获 ctrl+c 异常
用以下方法太挫了:
1
2
3
4
5
6
7try:
do_something
except Exception, e:
if "Key" in str(e):
print "ctrl+c caught..."
else:
do_something
这样显得优雅些:
1
2
3
4
5
6try:
do_something
except KeyboardInterrupt:
print "ctrl+c caught..."
except:
do_something
Python 的 “三元运算”
1 |
|
兼容 2.x 与 3.x 的 字符串输入:
vars(__builtins__).get('raw_input', input)("please input something")
相当于在 2.x 与 3.x 下均可使用 raw_input
原理:vars
用于返回对象 object 的 属性 和 属性值 的 字典对象。所以 vars(__builtins__)
返回的是 内建模块 的字典。get
呢,自然就是获取键值了,但是它有一个可选参数,用于在没有获取到键值的时候返回。即,.get('raw_input', input)
在没有获取到 'raw_input'
的时候,默认返回 input。所以,在 py2.x 看来,vars(__builtins__).get('raw_input', input)
的值就是 <function raw_input>
;在 py.x 看来,值就是 <function input(prompt=None, /)>
。Coooool ~
pprint.pprint() 编码
Python 中的 dict 含有非 ASCII 字符的时候,使用 pprint.pprint()
输出时显示的是 unicode。可以继承 pprint.PrettyPrinter
,重写 format
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#-*- coding:utf-8 -*-
import pprint
class MyPrettyPrinter(pprint.PrettyPrinter):
def format(self, object, context, maxlevels, level):
if isinstance(object, unicode):
return (object.encode('utf8'), True, False)
return pprint.PrettyPrinter.format(self, object, context, maxlevels, level)
d = {'foo': u'中文'}
pprint.pprint(d)
MyPrettyPrinter().pprint(d)
结果是
1
2{'foo': u'\u4e2d\u6587'}
{'foo': 中文}
for...else
1 |
|
sum 的妙用
1 |
|
给点颜色
给输出加点颜色的话,在 Python 中可以这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14def PutColor(string, color):
colors = {
u"gray": "2",
u"red": "31",
u"green": "32",
u"yellow": "33",
u"blue": "34",
u"pink": "35",
u"cyan": "36",
u"white": "37",
}
return u"\033[40;1;%s;40m%s\033[0m" % (colors[color], string)
固定行输出
控制光标位置的则可以用来固定打印行。
控制字符见这篇博文
如:
获得终端的大小
获得终端的大小,限制打印的文字数量,防止打印的时候出现换行
1 |
|
这个方法在 py3.x 是肯定可行的。在 py2.x 只有 Unix 可用。若想兼容,则可以:
lines, columns = os.popen('stty size', 'r').read().split()
注意,这里的 columns
与 lines
均为字符串。
Python 清屏
os.system("printf '\033c\e]50;ClearScrollback\a'")
'\033c\e]50;ClearScrollback\a'
这个是控制字符,见这篇博文
Python 与转义
转义
我们都知道 \
是用来转义的。
比如:
1
2
3In [1]: print "1\n1"
1
1
但是,如果我们需要输出 1\n1
呢?可以这样:
1
2In [2]: print r"1\n1"
1\n1
然而,不是所有时候都可以加 r
的,比如:
1
2
3
4
5In [5]: a = spider() # 假设这个是外来数据,返回 "1\n1"
...: print a
...:
1
1
这个时候,我们可以利用 repr
来解决这个需求:
> repr() 函数将对象转化为供解释器读取的形式。通常情况下 obj == eval(repr(obj))
这个等式是成立的。
这函数用在这里的转义处理中,实际上是将 \
变为了 \\
,
1
2
3
4In [6]: a = repr(spider()) # 假设这个是外来数据,返回 "1\n1"
...: print a
...:
1\n1
但是,repr 不仅仅处理 \
:
1
2
3
4
5
6
7
8
9In [11]: a = "'1'\n'1'"
...: print a
...: print "-"*10
...: print repr(a)
...:
'1'
'1'
----------
"'1'\n'1'" # 即为 print '"\'1\'\\n\'1\'"'
算是 repr 用于处理 \
的一个小陷阱
同样,string.encode('string_escape')
也是:
1
2In [372]: print "'1'\n'1'".encode('string_escape')
\'1\'\n\'1\'
更进一步的
1
2
3
4
5
6
7
8
9
10In [9]: a = "1\n1"
...: for i in range(5):
...: a = repr(a)
...: print a
...:
'1\n1'
"'1\\n1'"
'"\'1\\\\n1\'"'
'\'"\\\'1\\\\\\\\n1\\\'"\''
'\'\\\'"\\\\\\\'1\\\\\\\\\\\\\\\\n1\\\\\\\'"\\\'\''
如果仅仅是想转义 \
怎么办呢?(将 '1'\n'1'
变为 '1'\\n'1'
而不是 '"\'1\'\\n\'1\'"'
也不是 "\\'1\\'\\n\\'1\\'"
),可以用 string.replace("", "")
或者 re
。
1
2
3
4
5
6
7
8In [179]: s = "'1'\n'1'"
In [180]: print s
'1'
'1'
In [181]: print s.replace("\n", "\\n")
'1'\n'1'
s.replace("\n", "\\n")
只能转义 \n
,想要转义 \r
就又得加一个 replace。暂时还没有好办法,后续想到再加进来。
去除转义
1
2
3
4
5
6
7
8In [364]: myString = "spam\\neggs"
...: decoded_string = myString.decode('string_escape') # python2
...: print(decoded_string)
...:
spam
eggs
# py3.x: decoded_string = bytes(myString, "utf-8").decode("unicode_escape")
或者(兼容 py2.x 与 3.x)
1
2
3
4
5In [365]: import codecs
...: print(codecs.decode(myString, 'unicode_escape'))
...:
spam
eggs
' 字符串转中文
- python2 的解决办法:
string.decode('unicode_escape')
- python3 的解决办法:
string.encode('utf-8').decode('unicode_escape')
或者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
这个函数作用是处理转义序列,不止 ' 转中文,也可以将 1\\n1
=> 1[换行]1
等等。
re
中的 re.Unicode/re.U
处理 unicode 的时候很有用。具体用处如下:
1
2
3
4
5
6
7
8
9
10
11In [165]: re.findall("\w+", u'test test 我')
Out[165]: [u'test', u'test']
In [166]: re.findall(u"\w+", u'test test 我')
Out[166]: [u'test', u'test']
In [167]: re.findall(u"\w+", u'test test 我', re.U)
Out[167]: [u'test', u'test', u'\u6211']
In [168]: print u'\u6211'
我
py3.x 中默认启用
判断程序是否以 root 权限运行
1 |
|
生成时间序列
爆破字典为生日的时候,需要生成时间字典,如 20100101-20171231
1
2
3
4
5
6import pandas
data = pandas.date_range('20140101','20161231',freq='D').strftime('%Y%m%d') #freq 为时间间隔
for t in data:
print t #20140101-20161231
来呀快活呀