在Python中,一般称优雅的代码为Pythonic。以我的理解,所谓Pythonic就是用Python的方式写出简洁优美的代码。

今天我给大家分享5种简洁优美的代码,相信看完本篇文章后你会对如何编写Python有不一样的理解。

善用内置函数

合理使用数据结构

合理使⽤Python的⾼级并发⼯具

巧妙使⽤装饰器简化代码

Python中的设计模式

1、善用内置函数

1.1 enumerate类

enumerate 是⼀个类,但是⽤起来却跟函数⼀样⽅便。不使⽤ enumerate 可能是 Python 新⼿最容易被吐槽的地⽅了。enumerate 其实⾮常简单,接收⼀个可迭代对象,返回 index 和可迭代对象中的元素的组合。

不使⽤enumerate的时候
from __future__ import print_function
L = [ i*i for i in range(5) ]
index = 0
for data in L:
index += 1
print(index, ':', data)
正确使⽤enumerate的姿势:
L = [ i*i for i in range(5) ]
for index, data in enumerate(L, 1):
print(index, ':', data)
不使用enumerate需要4行代码,使用enumerate只需要2行代码。如果想把代码写得简洁优美,大家要时刻记住:在保证代码可读性的前提下,代码越少越好。
1.2 any
在内置函数中,像any和all这种函数,是大家都知道,并且觉得很简单,但是使用的时候就想不起来的。我们来看一个具体的例子。
以元组为例,如下所示:
(('t', 0, 'PRIMARY', 1, 'id', 'A', 0, None, None, '', 'BTREE', '', ''),)
我们现在要遍历一个二维的元组,然后判断是否存在Non_unique为0,Null列不为YES的记录。详细了解了具体实现以后,我们写下了下面的代码:
def has_primary_key():
for row in rows:
if row[1] == 0 and row[9] != 'YES':
return True
return False
如果我们使用any函数的话,代码将会更短。
def has_primary_key():
return any(row[1] == 0 and row[9] != 'YES' for row in rows):
2、善用内置函数
我们再来看一个类似的例子,获取元素且删除:
L = [1, 2, 3, 4]
last = L[-1]
L.pop()
print(last) # 删除元素
print(L) # 最终元素
-----result--------
4
[1, 2, 3]
这里我们又多此一举了。在调用L.pop()函数的时候,本身就会返回给我们需要pop的数,其实我们可以这样:
L = [1, 2, 3, 4]
last = L.pop()
print(last) # 删除元素
print(L) # 最终元素
-----result--------
4
[1, 2, 3]

3、合理使⽤Python的⾼级并发⼯具

很多时候,我们要用并发编程,并不用自己手动启动一个线程或进程,完全可以使用Python提供的并发工具。内置的map是单线程运行的,如果涉及到网络请求或者大量的cpu计算,则速度相对会慢很多,出现了并发的map,如下所示:

import requests
from multiprocessing import Pool
def get_website_data(url):
r = requests.get(url)
return r.url
def main():
urls = ['http://www.google.com',
'http://www.baidu.com',
'http://www.163.com']
pool = Pool(2)
print(pool.map(get_website_data, urls))
main()
为了与线程兼容,该模块还提供了multiprocessing.dummy,用以提供线程池的实现,如下所示:
from multiprocessing.dummy import Pool

使用Pool,我们可以快速的在线程池和进程池之间来回切换,最重要的是,使用高级的并发工具不那么容易出错。

4、巧妙使⽤装饰器简化代码

装饰器可能是Python面试中被问的最多的知识了。之所以如此频繁的出现,是因为,装饰器确实是个好东西。

举个例⼦,我们有两个模块,A模块要发消息给B模块,B模块检查A模块发送过来的参数,没有问题就进⾏处理,对于检查参数这个操作,如果我们使⽤装饰器的话,代码将会是下⾯这样:

import inspect
import functools
def check_args(parameters):
"""check parameters of action"""
def decorated(f):
"""decorator"""
@functools.wraps
def wrapper(*args, **kwargs):
"""wrapper"""
func_args = inspect.getcallargs(f, *a
msg = func_args.get('msg')
for item in parameters:
if msg.body_dict.get(item) is Non
return False, "check failed,
return f(*args, **kwargs)
return wrapper
return decorated
使⽤的时候:
class AsyncMsgHandler(MsgHandler):
@check.check_args(['ContainerIdentifier', 'MonitorSecretKey','InstanceID','UUID'])
def init_container(self, msg):
pass

5、Python中的设计模式

对Python的模块熟悉的⼈会知道,在Python中,模块只初始化⼀次,所有变量归属于某个模块,import机制是线程安全的。所以,模块本身是天然的单例实现。因此,我们可以借助模块来实现单例模式。

下⾯这个例⼦创建了⼀个函数,令其返回含有货币汇率的字典,这个函数可以被多次调⽤,但是,⼤部分情况下,汇率数据只获取⼀次就够了,⽆须每次调⽤时都获取⼀遍。

def get():
if not get.rates:
_URL = 'http://www.bankofcanada.ca/stats/
with urllib.request.urlopen(_URL) as file
for line in file:
# get.rates[key] = float(data)
pass
return get.rates
get.rates = {}

在这段代码中,尽管没有引⼊类,但我们依然把汇率数据做成了"单例数据值"。⼤家可以看到,在Python中,单例可以直接使⽤模块来实现,⾮常的简单。