不容错过的Python小贴士—技巧, 风格和最佳实践

— 改编自 Python: Tips, Tricks and Idioms

 

1. Dict的for循环中避免使用低效的iteritems() 和 keys()

In [1]:
a = {}
for i in xrange(0, 1000000):
    a[i] = i
print(type(a))
print(len(a))
<type 'dict'>
1000000
In [2]:
def for_func1():
    for x in a:
        pass

def for_func2():
    for x in a.keys():
        pass

def for_func3():
    for x,v in a.iteritems():
        pass
In [3]:
import timeit
print(timeit.timeit(for_func1, number=100))
print(timeit.timeit(for_func2, number=100))
print(timeit.timeit(for_func3, number=100))
1.22459793091
2.30621099472
2.17837190628

是不是快多了?

 

2. for循环中获得index神器: enumerate

In [4]:
students = ('James', 'Andrew', 'Mark')
In [5]:
for i, student in enumerate(students):
    print i, student
0 James
1 Andrew
2 Mark
In [6]:
students = {'James': 'male', 'Andrew':'male', 'Alice':'female'}
In [7]:
for i, student in enumerate(students):
    print i, student
0 James
1 Andrew
2 Alice

3. 想确定for循环完整结束, 用else吧…

In [8]:
for ele in ['a', 'b', 'c']:
    if ele == 'b':
        break
else: # no break
    print('for循环完整结束')
In [9]:
for ele in ['a', 'b', 'c']:
    if ele == 'd':
        break
else: # no break
    print('for循环完整结束')
for循环完整结束

4. 迭代工具之chain连接器

In [10]:
import itertools

#把所有元素放到一个list中
a=[[1],[2],[3,4],[5,6],[7,8,9]]
print list(itertools.chain(*a))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In [11]:
#甚至还能连接不同类型数据dict和list
b=[{'a': 1, 'b': 2},[2],[3,4],[5,6],[7,8,9]]
print list(itertools.chain(*b))
['a', 'b', 2, 3, 4, 5, 6, 7, 8, 9]

5. 迭代工具之排列组合

In [12]:
print list(itertools.permutations([1,2,3]))
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
In [13]:
print list(itertools.combinations([0,1,2,3], 3))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]

6. zip拉链函数

In [14]:
random_numbers = [1,2,3]
names = ('James', 'Andrew', 'Mark')
print zip(random_numbers, names)
d = dict(zip(random_numbers, names))
print d
[(1, 'James'), (2, 'Andrew'), (3, 'Mark')]
{1: 'James', 2: 'Andrew', 3: 'Mark'}
In [15]:
li=[['a','b','c'],['d','e','f']]
print zip(*li)
[('a', 'd'), ('b', 'e'), ('c', 'f')]
In [16]:
dots = [(1, 3), (2, 4), (3, 5)]
print zip(*dots)
[(1, 2, 3), (3, 4, 5)]

7. with语句的保护性

In [17]:
with open('/etc/passwd', 'r')as f:
    print f.read()
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
messagebus:x:102:106::/var/run/dbus:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
dnsmasq:x:104:65534:dnsmasq,,,:/var/lib/misc:/bin/false
avahi-autoipd:x:105:113:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
kernoops:x:106:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
rtkit:x:107:114:RealtimeKit,,,:/proc:/bin/false
saned:x:108:115::/home/saned:/bin/false
whoopsie:x:109:116::/nonexistent:/bin/false
speech-dispatcher:x:110:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
avahi:x:111:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
lightdm:x:112:118:Light Display Manager:/var/lib/lightdm:/bin/false
colord:x:113:121:colord colour management daemon,,,:/var/lib/colord:/bin/false
hplip:x:114:7:HPLIP system user,,,:/var/run/hplip:/bin/false
pulse:x:115:122:PulseAudio daemon,,,:/var/run/pulse:/bin/false
yanchao:x:1000:1000:yanchao,,,:/home/yanchao:/bin/bash
sshd:x:116:65534::/var/run/sshd:/usr/sbin/nologin
glances:x:117:126::/var/lib/glances:/bin/false
privoxy:x:118:65534::/etc/privoxy:/bin/false
postgres:x:119:128:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
redis:x:120:129:redis server,,,:/var/lib/redis:/bin/false
vagrant:x:1001:1002::/home/vagrant:

In [18]:
print(f)
<closed file '/etc/passwd', mode 'r' at 0x7fb77b785c90>

With 语句结束会自动关闭文件!

8. 数据结构之Counter–计数神器

In [19]:
import collections

print collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])
print collections.Counter({'a':2, 'b':3, 'c':1})
print collections.Counter(a=2, b=3, c=1)
Counter({'b': 3, 'a': 2, 'c': 1})
Counter({'b': 3, 'a': 2, 'c': 1})
Counter({'b': 3, 'a': 2, 'c': 1})
In [20]:
c = collections.Counter()
print 'Initial :', c

c.update('abcdaab')
print 'Sequence:', c

c.update({'a':1, 'd':5})
print 'Dict    :', c
Initial : Counter()
Sequence: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
Dict    : Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})
In [21]:
c = collections.Counter()
with open('/usr/share/dict/words', 'rt') as f:
    for line in f:
        c.update(line.rstrip().lower())
print 'Most common:'
for letter, count in c.most_common(3):
    print '%s: %7d' % (letter, count)
Most common:
s:   90113
e:   88833
i:   66986

9. 数据结构之defaultdict–任何数据转成dict的神器

In [22]:
from collections import defaultdict

order = (
('Mark', 'Steak'),
('Andrew', 'Veggie Burger'),
('James', 'Steak'),
('Mark', 'Beer'),
('Andrew', 'Beer'),
('James', 'Wine'),
)
#key已经确定, 返回value是list的工厂
group_order = defaultdict(list)

for name, menu_item in order:
    group_order[name].append(menu_item)

print group_order
defaultdict(<type 'list'>, {'James': ['Steak', 'Wine'], 'Andrew': ['Veggie Burger', 'Beer'], 'Mark': ['Steak', 'Beer']})
In [23]:
#key已经确定, 返回value是int的工厂
order_count = defaultdict(int)

for name, menu_item in order:
    order_count[menu_item] += 1

print order_count
defaultdict(<type 'int'>, {'Beer': 2, 'Steak': 2, 'Wine': 1, 'Veggie Burger': 1})

10. 数据结构之defaultdict–记住插入数据的顺序

In [24]:
from collections import OrderedDict

li_order1=['a','b','c','c']
li_order2=['c','b','a','c']

d1 =  OrderedDict()
d2 = OrderedDict()

for x in li_order1:
    d1[x] = 1
print d1
OrderedDict([('a', 1), ('b', 1), ('c', 1)])
In [25]:
for x in li_order2:
    d2[x] = 1
print d2
OrderedDict([('c', 1), ('b', 1), ('a', 1)])

11. 数据结构之namedtuple — 闪电般构造一个类

In [26]:
from collections import namedtuple
#namedtuple is a CLASS
Parts = namedtuple('Parts', 'id_num desc cost amount')
In [27]:
auto_parts = Parts(id_num='1234', desc='Ford Engine',
                   cost=1200.00, amount=10)
print auto_parts.id_num
1234
In [28]:
auto_parts = ('1234', 'Ford Engine', 1200.00, 10)
print auto_parts[2]
1200.0
In [29]:
id_num, desc, cost, amount = auto_parts
print id_num
Parts = {'id_num':'1234', 'desc':'Ford Engine',
                      'cost':1200.00, 'amount':10, 'profit': 10000}
parts = namedtuple('Parts', Parts.keys())(**Parts)
print parts
1234
Parts(profit=10000, amount=10, cost=1200.0, id_num='1234', desc='Ford Engine')
In [30]:
# define new type
BuildInput = namedtuple('BuildInput', ['name', 'files'])
# test scenarios
b1 = BuildInput('test_build_1', ['file1.txt', 'file2.txt'])

b2 = BuildInput(name='test_build_2', files=['file3.txt', 'file4.txt'])

another_b1 = BuildInput(name='test_build_1', files=['file1.txt', 'file2.txt'])

print b1 != b2
print b1 == another_b1
True
True

12. Python中的Getter 和 setter

In [31]:
class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

    # Getter and setter for dollars...
    @property
    def dollars(self):
        return self.total_cents // 100;
    @dollars.setter
    def dollars(self, new_dollars):
        self.total_cents = 100 * new_dollars + self.cents

    # And the getter and setter for cents.
    @property
    def cents(self):
        return self.total_cents % 100;
    @cents.setter
    def cents(self, new_cents):
        self.total_cents = 100 * self.dollars + new_cents
In [32]:
# with the final Money class. High five!
money = Money(27, 12)
message = "I have {:d} dollars and {:d} cents."
print(message.format(money.dollars, money.cents))
# "I have 27 dollars and 12 cents."

money.dollars += 2
money.cents += 20
print(message.format(money.dollars, money.cents))
# "I have 29 dollars and 32 cents."

# This works correctly, too.
money.cents += 112
print(message.format(money.dollars, money.cents))
# "I have 30 dollars and 44 cents."
I have 27 dollars and 12 cents.
I have 29 dollars and 32 cents.
I have 29 dollars and 144 cents.

How to code with no bugs

一行生成器与一行list写法区分

In [33]:
a = (x**2 for x in [1,2,3,4,5])

print(type(a))
for i in a:
    print(i)
<type 'generator'>
1
4
9
16
25
In [34]:
b = [x**2 for x in [1,2,3,4,5]]
print(b)
[1, 4, 9, 16, 25]

 

发布者

David 9

邮箱:yanchao727@gmail.com 微信: david9ml

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注