tcpdump太好玩了

我有个主机,专门用来做跳板来访问一些国外网站,也分享给了几个朋友。
速度一直很稳定,今早突然变得特别卡,所以就想看看是不是我们几个人同时在用。

详细的tcpdump请看tcpdump man page

1
2
root@chuanwu:~# tail -f tmp.log | pv > /dev/null
948KiB 0:01:35 [3.97KiB/s] [ <=> ]

看了下文件增长速度,还可以,让他跑一下午。拿到数据分析一下。

单机器性能监控

因为工作需要,整理了一些命令来查看机器的运行情况。

  • uptime

先uptime来看看平均负载,先对实例的负载有一个宏观的认识。

1
2
uptime
23:40 up 3 days, 15:35, 1 user, load averages: 2.12 2.37 2.32
  • dmesg

查看最近10条系统消息。

1
2
3
4
5
6
7
8
9
10
11
➜ ~ dmesg -T| tail -10
[Tue May 31 10:58:31 2016] docker0: port 1(vethcf80d8f) entered disabled state
[Tue May 31 10:58:31 2016] docker0: port 1(vethcf80d8f) entered disabled state
[Tue May 31 10:58:31 2016] device vethcf80d8f left promiscuous mode
[Tue May 31 10:58:31 2016] docker0: port 1(vethcf80d8f) entered disabled state
[Tue May 31 18:22:56 2016] device veth0daef81 entered promiscuous mode
[Tue May 31 18:22:56 2016] IPv6: ADDRCONF(NETDEV_UP): veth0daef81: link is not ready
[Tue May 31 18:22:56 2016] IPv6: ADDRCONF(NETDEV_CHANGE): veth0daef81: link becomes ready
[Tue May 31 18:22:56 2016] docker0: port 1(veth0daef81) entered forwarding state
[Tue May 31 18:22:56 2016] docker0: port 1(veth0daef81) entered forwarding state
[Tue May 31 18:23:11 2016] docker0: port 1(veth0daef81) entered forwarding state
  • vmstat
1
2
3
4
5
6
7
8
9
10
11
➜ ~ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 124392 147184 312408 0 0 0 4 4 8 1 1 99 0 0
0 0 0 124384 147184 312408 0 0 0 0 221 519 0 0 100 0 0
0 0 0 124384 147184 312408 0 0 0 12 206 494 0 1 99 0 0
# r 表示队列长度
# free 表示空闲内存
# si, so 表示换入的内存和换出的内存
# us, sy, id, wa, st:CPU时间的不同组成部分,是所有CPU的平均数

统计虚拟内存信息。参数1表示,统计粒度为1秒。

  • mpstat
1
2
3
4
5
6
7
8
9
10
11
12
[root@chuanwu:~] # mpstat -P ALL 1
Linux 3.13.0-32-generic (dtstack-dev1) 07/22/2016 _x86_64_ (2 CPU)
11:09:04 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
11:09:05 PM all 24.75 1.49 5.94 14.85 0.99 0.00 0.00 0.00 0.00 51.98
11:09:05 PM 0 26.53 1.02 7.14 8.16 0.00 0.00 0.00 0.00 0.00 57.14
11:09:05 PM 1 23.23 2.02 4.04 21.21 1.01 0.00 0.00 0.00 0.00 48.48
11:09:05 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
11:09:06 PM all 33.00 3.50 4.50 23.00 1.00 0.00 1.00 0.00 0.00 34.00
11:09:06 PM 0 31.68 4.95 3.96 22.77 1.98 0.00 0.99 0.00 0.00 33.66
11:09:06 PM 1 34.65 2.97 4.95 22.77 0.99 0.00 0.00 0.00 0.00 33.66

打印每个CPU的状况。

  • pidstat
1
2
3
4
5
[root@chuanwu:~] # pidstat -p 12339
Linux 3.13.0-32-generic (dtstack-dev1) 07/22/2016 _x86_64_ (2 CPU)
11:10:58 PM UID PID %usr %system %guest %CPU CPU Command
11:10:58 PM 0 12339 0.19 0.13 0.00 0.31 0 python

根据pid来查询性能。

  • iostat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@chuanwu:~] # iostat -xz 1
Linux 3.13.0-32-generic (dtstack-dev1) 07/22/2016 _x86_64_ (2 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
15.44 0.29 4.05 6.55 0.11 73.56
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
xvda 0.00 3.87 0.62 3.93 7.57 75.80 36.60 0.13 27.45 6.79 30.74 1.31 0.60
xvdb 0.12 25.28 1.86 93.07 37.17 1034.45 22.58 0.58 6.09 5.71 6.10 1.76 16.70
avg-cpu: %user %nice %system %iowait %steal %idle
32.83 3.03 6.06 20.20 0.00 37.88
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
xvda 0.00 0.00 1.00 0.00 8.00 0.00 16.00 0.00 4.00 4.00 0.00 4.00 0.40
xvdb 0.00 72.00 0.00 215.00 0.00 1164.00 10.83 0.50 2.33 0.00 2.33 2.33 50.00
avg-cpu: %user %nice %system %iowait %steal %idle
22.61 4.02 3.02 24.12 0.00 46.23
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
xvda 0.00 20.00 0.00 4.00 0.00 100.00 50.00 0.02 6.00 0.00 6.00 4.00 1.60
xvdb 0.00 76.00 0.00 228.00 0.00 1232.00 10.81 0.53 2.32 0.00 2.32 2.30 52.40
# util是个重要参数,如果超过60%需要特殊关注。
  • free
1
2
3
4
5
6
[root@chuanwu:~] # free -m
total used free shared buffers cached
Mem: 7983 7501 482 2 179 3635
-/+ buffers/cache: 3687 4296
Swap: 0 0 0
# 如果buffers,cache接近0,需要关注下iostat,磁盘I/O可能过高。
  • sar -n DEV 1
1
2
3
4
5
6
7
8
9
[root@dtstack-dev1:~] # sar -n DEV 1
Linux 3.13.0-32-generic (dtstack-dev1) 07/23/2016 _x86_64_ (2 CPU)
03:36:20 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
03:36:21 PM eth0 28.00 24.00 4.37 1.68 0.00 0.00 0.00 0.00
03:36:21 PM eth1 66.00 75.00 11.97 9.44 0.00 0.00 0.00 0.00
03:36:21 PM lo 219.00 219.00 81.38 81.38 0.00 0.00 0.00 0.00
03:36:21 PM veth7ce7c34 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
03:36:21 PM docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

查看网络接口的吞吐量。

  • sar -n TCP, ETCP 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@chuanwu:~] # sar -n TCP,ETCP 1
Linux 3.13.0-32-generic (dtstack-dev1) 07/23/2016 _x86_64_ (2 CPU)
03:43:02 PM active/s passive/s iseg/s oseg/s
03:43:03 PM 3.00 2.00 265.00 272.00
03:43:02 PM atmptf/s estres/s retrans/s isegerr/s orsts/s
03:43:03 PM 0.00 0.00 1.00 0.00 0.00
03:43:03 PM active/s passive/s iseg/s oseg/s
03:43:04 PM 19.00 30.00 1104.00 1097.00
03:43:03 PM atmptf/s estres/s retrans/s isegerr/s orsts/s
03:43:04 PM 0.00 6.00 0.00 0.00 0.00
03:43:04 PM active/s passive/s iseg/s oseg/s
03:43:05 PM 74.00 48.00 2349.00 2360.00

查看tcp相关指标。

  • top

Ref:

  1. 性能之巅

  2. 10条命令,一分钟分析Linux性能问题

刷leetcode

编程,我觉得要经历三个阶段。

  • make it run
  • make it work
  • make it faster

目前,我只做到了第二步。
等刷完,再去discuss板块里看看大神们是怎么优化的。

代码在这Leetcode

刷了有十几题,最大的感受就是无论什么样的题,总有大神,能用最短最精简的代码来搞定,而且运行时间要比你的短…

我觉得今天太忙真是一个说服自己的好托辞。

最近太忙, 没空看书。
最近项目需求多,没时间去刷题。
改个bug,累死了,今天先歇会。

诸如此类。

给自己定目标定一年了,说要刷leetcode,然后呢,一年之后,还是一题没刷。好羞耻…

一共也就358道题。

想起胡适先生的日记。

7月4日
新开这本日记,也为了督促自己下个学期多下些苦功。先要读完手边的莎士比亚的《亨利八世》……

7月13日
打牌。

7月14日
打牌。

7月15日
打牌。

7月16日
胡适之啊胡适之!你怎么能如此堕落!先前订下的学习计划你都忘了吗?
子曰:“吾日三省吾身。”…不能再这样下去了!

7月17日
打牌。

7月18日
打牌。

不想扯了。直接开刷吧。

leetcode

关于Python的property,yield,slot

yield

要理解yield,先看两段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fib(n):
a, b = 0, 1
for _ in xrange(n):
yield a
a, b = b, a + b
def chunks(l, n):
for i in range(0, len(l), n):
yield l[i:i+n]
def split_by_age(children, n):
ages = set(i.age for i in children)
for age in ages:
yield age, chunks(list(set(i for i in children if i.age == age)), n)

yield和return很像。不过yield返回的是一个生成器。生成器和迭代器很像,不过生成器只能遍历一次,因为每次next()被调用时,生成器会返回它脱离的位置,就是说它只能记住语句最后一次执行的位置和所有的数据值)。

property

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

1
2
s = Student()
s.score = 9999 or 'hello world'

这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,通过这两个方法就能限制score了。

1
2
3
4
5
6
7
8
9
10
11
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

这样,我们就能对score进行参数检查了。

1
2
3
4
5
6
7
8
>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!

但是看着代码,好烦,一点也不Pythonic。

Python里面有个built-in方法property可以胜任这个工作。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

如果不定义@score.setter,property默认只是给score增加了一个getter属性,它是作为一个只读属性存在。

requests里面有段源码,可以参考下。

1
2
3
4
5
6
7
8
9
10
11
@property
def unverifiable(self):
return self.is_unverifiable()
@property
def origin_req_host(self):
return self.get_origin_req_host()
@property
def host(self):
return self.get_host()

slots

看段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Class(object):
def __init__(self, name, identifier):
self.name = name
self.identifier = identifier
m = Class(1,2)
m.age = 1
class Class(object):
__slots__ = ['name', 'identifier']
def __init__(self, name, identifier):
self.name = name
self.identifier = identifier
m = Class(1,2)
m.age = 1
---------------------------------------------------------------------------
Traceback (most recent call last)
<ipython-input-12-b504c75d350a> in <module>()
----> 1 m.age = 1
AttributeError: 'MyClass' object has no attribute 'age'
class MyClass(Class):
pass
c = Class()
---------------------------------------------------------------------------
Traceback (most recent call last)
<ipython-input-14-2e11f7fbc2a5> in <module>()
----> 1 c = Class()
TypeError: __init__() takes exactly 3 arguments (1 given)
c = Class(1,2)
c.age =1

使用slots有以下好处。

  • slots会限定只能设定这两个属性
  • 继承的子类不受限制
  • 能省点内存。

with

with这个关键词,挺常用的。今天偶然翻到一篇PEP,才发现原来一个with干了这么多事。

大概是这么个逻辑,PEP-343里描述得更详细,推荐读一下。

1
2
3
4
5
6
7
8
9
10
@contextmanager
def opening(filename):
f = open(filename)
try:
yield f
finally:
f.close()
with f = opening(filename):
...read data from f...

super

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A(object):
def foo(self):
print 'A'
class B(A):
def foo(self):
print 'B'
super(B, self).foo()
class C(A):
def foo(self):
print 'C'
super(C, self).foo()
class D(B,C):
def foo(self):
print 'D'
super(D, self).foo()
d = D()
d.foo()
# DBCA

requests源码阅读

对网络请求一直很感兴趣,加上requests的代码很Pythonic,所以我打算读一下源码。

我fork的requests版本为2.8.1

先从cookies入手,了解整个项目,我也会对在阅读过程感觉不明白或者有趣的地方进行拓展。

网络小白,如有错误,请指正。

So, 开始吧?

cookies里面主要封装了几个类。

  • MockRequest
  • MockResponse
  • RequestsCookieJar
  • CookieConflictError

MockRequest主要是封装了一个requests.Request来模拟urllib2.Request。
里面有三个方法,挺好玩的。

requests源代码看起来其实蛮费力的,需要对HTTP有很深的认识才行。

所以,接下来,打算给自己设定两个目标。

  • 阅读HTTP权威指南
  • 熟悉pytest框架

Pratical VIM笔记

1. .重复上一次操作

2. >G会增加从当前行到文档末尾的缩进

组合#1和#2来试试。

1
2
3
4
5
6
7
8
9
10
11
Txt:
1 Line One
2 Line Two
3 Line Three
Command:>Gj.j.j.
1 Line One.
2 Line Two.
3 Line Three.

3. 行尾添加分号

1
2
3
4
5
6
7
8
9
10
11
12
13
# vim中A=$a
Txt:
1 Line One
2 Line Two
3 Line Three
Command:A;<Esc>j.j.
1 Line One.;
2 Line Two.;
3 Line Three.;

4. 重复进行一些操作

1
2
3
4
5
6
Txt:
I have some delicious apples.
Command: c2wbought some<Esc>
I have bought some apples.

5. VIM一些操作符

Command Usage
g~ 反转大小写
gu 转成小写
gU 转成大写

可视模式下

Command Usage
~ 反转大小写
u 转成小写
U 转成大写

Python中的_, __, __xx__

看MySQL看得有点头大,写点好玩的吧。来看看_, __以及__xx__

_

_在Python中,有三种用途:

  • python shell中,来保存上次返回的结果。
1
2
3
4
5
6
7
In [1]: a, b = 3, 4
In [2]: a+b
Out[2]: 7
In [3]: _
Out[3]: 7
  • i18n模块中会用print _("Hello World")
    如果在翻译文件中定义了
1
2
msgid "Hello World"
msgstr "世界你好"

执行print _("Hello World"),则会显示世界你好。其实,这是因为Django i18n在翻译时会把gettext缩写成( from django.utils.translation import ugettext as )。

  • 遇到一次性的变量时,会给它起名叫_

在Python Cookbook中,有这样一段源码。

1
2
>>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]
>>> _, shares, price, _ = data >>> shares 50 >>> price 91.1

此外,在可以在类的方法或属性前加一个“_”单下划线,意味着该方法或属性不应该去调用,它并不属于API。
Django中有段源码:

1
2
3
4
5
6
7
8
9
10
class BaseForm(StrAndUnicode):
def _get_errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)

_表示该方法是私有的,不应该访问。

__

__避免子类覆盖其内容。

__xx__

__xx__经常是操作符或本地函数调用的magic methods

几个有趣的Python模块

glances

1
2
3
pip install glances
glances

能实时看到自己主机的信息。效果很赞。

when.py

直接上demo。还是很简洁的。

1
2
3
4
5
6
7
8
9
>>> import when
>>> when.timezone()
'Asia/Shanghai'
>>> when.today()
datetime.date(2013, 5, 14)
>>> when.tomorrow()
datetime.date(2013, 5, 15)
>>> when.now()
datetime.datetime(2013, 5, 14, 21, 2, 23, 78838)

fn.py

fn.py,最近正在学习的一个函数式编程模块,也很酷。
结合fn.py之后的lambda语句更加简洁,比如:

1
2
3
from fn import _
assert list(map(_ * 2, range(5))) == [0,2,4,6,8]
assert list(filter(_ < 10, [9,10,11])) == [9]

sh

对这个模块简直大爱。sh可以让py很完美地兼容bash。比如

1
2
3
4
5
6
from sh import git
print git.branch("-v")
# result
* master commit-id commit-msg

So cool!

那我们可以用这个模块做一些更炫酷的事情。比如我每天都需要查看服务器日志。

我可以通过sh模块,先scp我需要的日志下来,然后程序分析,对于需要实时盯着的日志,我们还可以引入tail -f来配合。好吧,我在一本正经地胡说八道。随便一个log文件,都要过g,怎么scp…
举个栗子:


from sh import tail

for line in tail("-f", "/var/log/some_log_file.log", _iter=True):
    print line

这样就可以tail日志了。

Python 2中的字符序列

Python 2 有两种表示字符序列的类型
• str (原始的八位值)
• unicode

注意: Python 2的unicode和Python 3的str都没有关联相应的进制编码形式。
所以在把unicode转化成二进制数据时,需要指明encode方法,反之,则需要
指定decode方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
def to_unicode(unicode_or_str):
if isinstance(unicode_or_str, str):
value = unicode_or_str.decode('utf-8')
else:
value = unicode_or_str
return value
def to_str(unicode_or_str):
if isinstance(unicode_or_str, unicode):
value = unicode_or_str.encode('utf-8')
else:
value = unicode_or_str
return value

unicode是为了解决各种编码方案不一致而提出来的。在Python 2中,也是通过unicode来解决编码冲突这个问题。unicode相当于是一种中间编码,可以将各种类型的str来decode成unicode,也可以把unicode通过encode来转化成在某种编码下的str。

把msg转化成utf-8编码,存成str

1
2
3
4
5
# -*- coding:utf-8 -*-
msg = u'小公主GG'
encoded_msg = msg.encode('utf-8')
print repr(msg)
# \xe5\xb0\x8f\xe5\x85\xac\xe4\xb8\xbbGG

相反的,

1
2
3
4
5
6
7
# -*- coding:utf-8 -*-
msg = '\xe5\xb0\x8f\xe5\x85\xac\xe4\xb8\xbbGG'
decoded_msg = msg.decode('utf-8')
print decoded_msg
# 小公主GG

Let's get pythonic

1. 警惕eval()带来的安全威胁

即使信任该字符串,最好还是应该使用ast.literal_eval()来代替。因为后者会检查字符串,是否是有效的python数据类型,从而避免一些风险。

2. 转换成浮点数来做除法

Python 2.7可以引入

from  __future__ import division

来避免除法运算的结果被截取,其实,这个模块就是为了把Python 2 不兼容的关键字和特性通过 __future__模块导入。在Python 2 中表现 Python 3.x 中的整除。

有兴趣的话,可以读一下PEP-0238

3. 异常处理

  • 保证异常处理中的代码量足够精简
  • 尽量避免直接像下面这样
1
2
3
4
5
6
try:
do somethind()
except Exception:
raise Exception
finally:
print 'finally'

Tip
在执行finally时,有个trap。
如果try模块中有异常,很不幸,finally模块中也存在一个异常的话,那try模块中的异常会被屏蔽。

4. 修饰器

先来看个最基本的例子:

1
2
3
4
5
6
7
8
9
10
11
12
def view_func(fn):
def wrapper():
print 'Ready?'
fn()
print 'Done!'
@view_func
def test():
print '*'*20
test()

给函数做一个缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from functools import wraps
def memo(fn):
cache = {}
miss = object()
@wraps(fn)
def wrapper(*args):
#从cache中查找,如果不存在则调用函数,重新添加到cache里面
result = cache.get(args, None)
if not result:
result = fn(*args)
cache[args] = result
return result
return wrapper
@memo
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)

5. repr()到底是什么

str()函数是用户在print时调用,用来显示给用户看的;repr()则是给解释器来看的,意思就是说,你repr()得到的结果,直接eval(repr(obj))就是obj本身。

6. 一个由reverse()引发的很有意思的问题

1
2
3
4
5
6
7
8
9
10
11
In [1]: m = [1, 2, 3, 4]
In [2]: n = m
In [3]: m.reverse()
In [4]: print m
[4, 3, 2, 1]
In [5]: print n
[4, 3, 2, 1]

Interesting! m,n竟然还是相等的。Python Docs上写道

1
2
list.reverse()
Reverse the elements of the list in place.

in place是个关键词。意思就是说它并没有做浅拷贝,而是直接修改内存上的数据(在reverse操作之前,m和n是共用同一个内存地址的,而reverse之后,m并没有做浅拷贝,所以m,n还是使用同一个内存)。

怎么样能让m,n做浅拷贝呢?使用[::-1]或者reversed()来替代即可。

7. 深浅拷贝

拓展一下6里所说的,我们来试下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
In [1]: a = [1,2,3, [4,5]]
In [2]: b = list(a)
In [3]: a[0] = 100
In [4]: a[3][0] = 999
In [5]:
In [5]:a
[100, 2, 3, [999, 5]]
In [6]:b
[1, 2, 3, [999, 5]]
In [21]:id(a[3])
4392396272
In [22]:id(b[3])
4392396272

可以看到,里面的列表还是变化了。打印id一看,其实内嵌的列表还是共用同一个内存地址。

copy.deepcopy来解决就好。

说个题外话,a = b = []看着很酷,其实,很有可能在之后的使用中遇到不明bug。

8. +join的问题

问题起因,在我看requests源码时,看到的一段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@property
def path_url(self):
"""Build the path URL to use."""
url = []
p = urlsplit(self.full_url)
# Proxies use full URLs.
if p.scheme in self.proxies:
return self.full_url
path = p.path
if not path:
path = '/'
url.append(path)
query = p.query
if query:
url.append('?')
url.append(query)
return ''.join(url)

很有意思的一点就是,作者在构造url时,他不是用+,而是特别喜欢用join。很有意思,一查才知道,the former is a very common and catastrophic mistake when building large strings. mark下,以后注意。

9. 简单的比较

1
2
3
4
5
6
7
8
9
10
11
In [1]: a = 10
In [2]: b = 12
In [3]:
In [3]: print 1 < a < b < 15
True
In [4]: print 1 < a < b < 10
False

直接链式比较。

再比如,

1
candidate = 'Jerry' if Jerry else 'Tom'

再比如,

10. else能有多酷

Python的else有点不太按常理出牌。
比如,

1
2
3
4
5
6
7
8
9
In [5]: lst = [1, 2, 3, 4, 5]
In [6]: for i in enumerate(lst):
...: if i == 10:
...: print 'found'
...: else:
...: print 'not found'
...:
not found

再比如,

1
2
3
4
5
6
7
8
In [9]: try:
...: a = 1
...: except IOError:
...: print 'IO Error'
...: else:
...: print 'succeed'
...:
succeed

11. 字典的默认值

1
2
3
dic = {'name':'XTT', 'age':9, 'occupation':'Front end engineer',}  
 
dic['phone'] = dic.get('phone','114')

12. zip~

通过zip把两个tuple结合一起,然后转成dict。

1
2
3
4
5
6
7
8
9
In [16]: key_lst = ('name', 'age', 'occupation')
In [17]: value_lst = ('XTT', 9, 'Front end engineer')
In [18]: print zip(key_lst, value_lst)
[('name', 'XTT'), ('age', 9), ('occupation', 'Front end engineer')]
In [19]: print dict(zip(key_lst, value_lst))
{'age': 9, 'name': 'XTT', 'occupation': 'Front end engineer'}