python 代码地道、优雅、高效、简洁的常用技巧

  Python在性能方面不卓越,但是使用一些小技巧,可以提高Python程序的性能,避免不必要的资源浪费。Python最大的优点之一就是语法简洁,好的代码就像伪代码一样,干净、整洁、一目了然。要写出 Pythonic(优雅的、地道的、整洁的)代码,需要多看多学大牛们写的代码,github 上有很多非常优秀的源代码值得阅读,比如:requests、flask、tornado,下面列举一些常见的Pythonic写法。

1、列表推导式

>>> chars = [ c for c in 'python' ]
>>> chars
['p', 'y', 't', 'h', 'o', 'n']

2、字典推导式

>>> dict1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
>>> double_dict1 = {k:v*2 for (k,v) in dict1.items()}
>>> double_dict1
{'a': 2, 'b': 4, 'c': 6, 'd': 8, 'e': 10}

3、集合推导式

>>> set1 = {1,2,3,4}
>>> double_set = {i*2 for i in set1}
>>> double_set
{8, 2, 4, 6}

4、合并字典

>>> x = {'a':1,'b':2}
>>> y = {'c':3, 'd':4}
>>> z = {**x, **y}
>>> z
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

5、复制列表

>>> nums = [1,2,3]
>>> nums[::]
[1, 2, 3]
>>> copy_nums = nums[::]
>>> copy_nums
[1, 2, 3]

6、反转列表

>>> reverse_nums = nums[::-1]
>>> reverse_nums
[3, 2, 1]

 PACKING / UNPACKING/

7、变量交换

>>> a,b = 1, 2
>>> a ,b = b,a
>>> a
2
>>> b
1

8、高级拆包

>>> a, *b = 1,2,3
>>> a
1
>>> b
[2, 3]

或者

>>> a, *b, c = 1,2,3,4,5
>>> a
1
>>> b
[2, 3, 4]
>>> c
5

9、函数返回多个值(其实是自动packing成元组)然后unpacking赋值给4个变量

>>> def f():
...     return 1, 2, 3, 4
...
>>> a, b, c, d = f()
>>> a
1
>>> d
4

10、列表合并成字符串

>>> " ".join(["I", "Love", "Python"])
'I Love Python'

11、链式比较

>>> if a > 2 and a < 5:
...     pass
...
>>> if 2<a<5:
...     pass

12、yield from

# 没有使用 field from
def dup(n):
    for i in range(n):
        yield i
        yield i

# 使用yield from
def dup(n):
    for i in range(n):
    yield from [i, i]

for i in dup(3):
    print(i)

>>>
0
0
1
1
2
2

13、in 代替 or

>>> if x == 1 or x == 2 or x == 3:
...     pass
...
>>> if x in (1,2,3):
...     pass

14、使用字典映射来替换条件搜索(字典代替多个if else)

def fun(x):
    if x == 'a':
        return 1
    elif x == 'b':
        return 2
    else:
        return None

def fun(x):
    return {"a": 1, "b": 2}.get(x)
def fun(x):
    if x == 1:
       b = 10
    elif x == 5:
        b = 8
    else:
        ...

def fun(x):
    d = {1:10, 5:8, ...}
    b = d[x]

15、有下标索引的枚举

>>> for i, e in enumerate(["a","b","c"]):
...     print(i, e)
...
0 a
1 b
2 c

16、生成器

注意区分列表推导式,生成器效率更高

>>> g = (i**2 for i in range(5))
>>> g
<generator object <genexpr> at 0x10881e518>
>>> for i in g:
...     print(i)
...
0
1
4
9
16

17、默认字典 defaultdict

>>> d = dict()
>>> d['nums']
KeyError: 'nums'
>>>

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d["nums"]
[]

18、字符串格式化

>>> lang = 'python'
>>> f'{lang} is most popular language in the world'
'python is most popular language in the world'

19、列表中出现次数最多的元素

>>> nums = [1,2,3,3]
>>> max(set(nums), key=nums.count)
3

或者
from collections import Counter
>>> Counter(nums).most_common()[0][0]
3

20、读写文件

>>> with open("test.txt", "w") as f:
...     f.writelines("hello")

21、判断对象类型,可指定多个类型

>>> isinstance(a, (int, str))
True

22、类似的还有字符串的 startswith,endswith

>>> "http://foofish.net".startswith(('http','https'))
True
>>> "https://foofish.net".startswith(('http','https'))
True

23、__str____repr__ 区别

>>> str(datetime.now())
'2018-11-20 00:31:54.839605'
>>> repr(datetime.now())
'datetime.datetime(2018, 11, 20, 0, 32, 0, 579521)'

前者对人友好,可读性更强,后者对计算机友好,支持 obj == eval(repr(obj))

24、使用装饰器

def makebold(f):
return lambda: "<b>" + f() + "</b>"

def makeitalic(f):
return lambda: "<i>" + f() + "</i>"

@makebold
@makeitalic
def say():
return "Hello"

>>> say()
<b><i>Hello</i></b>

不使用装饰器,可读性非常差

def say():
return "Hello"

>>> makebold(makeitalic(say))()
<b><i>Hello</i></b>

25、尽量使用生成器代替列表

##不推荐
def my_range(n):
    i = 0
    result = []
    while i &amp;lt; n:
        result.append(fn(i))
        i += 1
    return result  #  返回列表

##推荐
def my_range(n):
    i = 0
    result = []
    while i &amp;lt; n:
        yield fn(i)  #  使用生成器代替列表
        i += 1
*尽量用生成器代替列表,除非必须用到列表特有的函数。

26、中间结果尽量使用imap/ifilter代替map/filter

##不推荐
reduce(rf, filter(ff, map(mf, a_list)))

##推荐
from itertools import ifilter, imap
reduce(rf, ifilter(ff, imap(mf, a_list)))
*lazy evaluation 会带来更高的内存使用效率,特别是当处理大数据操作的时候。

27、使用any/all函数

any(x)判断x对象是否为空对象,如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true("or")

all(x)如果all(x)参数x对象的所有元素不为0、''、False或者x为空对象,则返回True,否则返回False("and")

##不推荐
found = False
for item in a_list:
    if condition(item):
        found = True
        break
if found:
    # do something if found...  

##推荐
if any(condition(item) for item in a_list):
    # do something if found...

28、使用 with 忽视异常(仅限Python 3)

##不推荐
try:
    os.remove("somefile.txt")
except OSError:
    pass

##推荐
from contextlib import ignored  # Python 3 only

with ignored(OSError):
    os.remove("somefile.txt")

 29、属性(property)

##不推荐
class Clock(object):
    def __init__(self):
        self.__hour = 1
    def setHour(self, hour):
        if 25 &amp;gt; hour &amp;gt; 0: self.__hour = hour
        else: raise BadHourException
    def getHour(self):
        return self.__hour

##推荐
class Clock(object):
    def __init__(self):
        self.__hour = 1
    def __setHour(self, hour):
        if 25 &amp;gt; hour &amp;gt; 0: self.__hour = hour
        else: raise BadHourException
    def __getHour(self):
        return self.__hour
    hour = property(__getHour, __setHour)

30、 使用 with 处理加锁

##不推荐
import threading
lock = threading.Lock()

lock.acquire()
try:
    # 互斥操作...
finally:
    lock.release()

##推荐
import threading
lock = threading.Lock()

with lock:
    # 互斥操作...

31、 使用局部变量

尽可能使用局部变量替代全局变量,可以是程序易于维护并且有助于提高性能节约成本。

在模块命名空间中将变量替换为局部变量,例如ls = os.linesep。一方面,可以提高程序性能,因为局部变量的搜素速度更快;另一方面,用短标识替换长模块变量,提高可阅读性。

32、减少函数调用的数量

(1)当需要确定对象类型时,使用isinstance()方法最好,id()次之,type()最差。

(2)为了避免重复计算,不要把重复操作作为参数放入循环中。

(3)使用模块X中的函数或者对象Y时,应该用from X import Y,而不是import X; X.Y。因此,当使用Y时,可以减少一次查询(解析器不必先找到模块X,然后在模块X的字典中查找Y)。

33、用生成器表达式替换列表解析

列表解析生成整个列表,会对大量数据的迭代产生负面作用。

而生成器表达式不会。生成器表达式不会创建一个列表,相反返回一个生成器,在需要的时候生成具体值(延迟的),这种方式对内存友好。

34、使用三元操作符来进行条件赋值

x = 10 if (y == 9) else 20

同样地,我们可以对类做这种操作:

x = (classA if y == 1 else classB)(param1, param2)

在上面的例子里 classA 与 classB 是两个类,其中一个类的构造函数会被调用。

下面是另一个多个条件表达式链接起来用以计算最小值的例子:

def small(a, b, c):
    return a if a <= b and a <= c else (b if b <= a and b <= c else c)

print(small(1, 0, 1))
print(small(1, 2, 2))
print(small(2, 2, 3))
print(small(5, 4, 3))

#Output
#0 #1 #2 #3

我们甚至可以在列表推导中使用三元运算符:

[m**2 if m > 10 else m**4 for m in range(50)]

#=> [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561, 10000, 121, 144, 169, 196, 225, 256, 289, 32

35、join函数组合多个字符串

test = ['I', 'Like', 'Python', 'automation']
str = '|'.join(test)
print(str)

结果:“I|like|python|automation”

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值