久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

如何優(yōu)雅高效地使用Python——這些Python技巧你必須學(xué)會,!

 天上飛雞 2020-10-17

前言

目前Python已經(jīng)更新到了3.7版本,不必多說,,Python 3比Python 2更是多出了許多新的功能,。Python是一門友好的語言,,其區(qū)別于以往C++,Java的特點不僅是代碼易于閱讀,,同時代碼也更加優(yōu)雅簡潔,,實現(xiàn)同樣的功能相對于Python只需要短短幾行代碼,這給予了開發(fā)人員更大的便利,,同時也易于初學(xué)者學(xué)習(xí),。本文將介紹Python中一些有趣實用的(代碼)功能,希望這些代碼能夠幫助大家更加輕松優(yōu)雅地解決一些問題,。
注:本博客代碼結(jié)果均為Python 3.6版本運行結(jié)果

Python之禪

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea – let’s do more of those!

Python之禪 by Tim Peters

優(yōu)美勝于丑陋(Python以編寫優(yōu)美的代碼為目標(biāo))
明了勝于晦澀(優(yōu)美的代碼應(yīng)當(dāng)是明了的,,命名規(guī)范,風(fēng)格相似)
簡潔勝于復(fù)雜(優(yōu)美的代碼應(yīng)當(dāng)是簡潔的,,不要有復(fù)雜的內(nèi)部實現(xiàn))
復(fù)雜勝于凌亂(如果復(fù)雜不可避免,,那代碼間也不能有難懂的關(guān)系,要保持接口簡潔)
扁平勝于嵌套(優(yōu)美的代碼應(yīng)當(dāng)是扁平的,,不能有太多的嵌套)
間隔勝于緊湊(優(yōu)美的代碼有適當(dāng)?shù)拈g隔,,不要奢望一行代碼解決問題)
可讀性很重要(優(yōu)美的代碼是可讀的)
即便假借特例的實用性之名,也不可違背這些規(guī)則(這些規(guī)則至高無上)
不要包容所有錯誤,,除非您確定需要這樣做(精準(zhǔn)地捕獲異常,,不寫 except:pass 風(fēng)格的代碼)
當(dāng)存在多種可能,不要嘗試去猜測
而是盡量找一種,,最好是唯一一種明顯的解決方案(如果不確定,,就用窮舉法)
雖然這并不容易,因為您不是 Python 之父(這里的 Dutch 是指 Guido )
做也許好過不做,,但不假思索就動手還不如不做(動手之前要細思量)
如果您無法向人描述您的方案,,那肯定不是一個好方案;反之亦然(方案測評標(biāo)準(zhǔn))
命名空間是一種絕妙的理念,,我們應(yīng)當(dāng)多加利用(倡導(dǎo)與號召)

Python:優(yōu)雅高效的寫法

多變量賦值

當(dāng)你想要初始化多個變量的時候:

  1. Bad
x = []y = []z = []
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  1. Better
x, y, z = [], [], []
  • 1
  • 1

這樣做的話代碼更加簡潔,,同時可讀性更高

變量交換

  1. Bad
# edchange x and yt = xx = yy = t
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  1. Better
# edchange x and yx, y = y, x
  • 1
  • 2
  • 1
  • 2

這樣做的話不止代碼簡潔,讓人一眼就能看出是要交換變量,,同時也能免去考慮中間變量賦值的先后順序,,并且后者的效率更是高于前者。

格式化字符串

如果你想要格式化輸出一串字符串,,你會怎么做,?

  1. Bad
name = 'James'country = 'USA'string = 'My name is %s, from %s, I love %s' % (name, country, country)>>> string'My name is James, from USA, I love USA'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. Better
name = 'James'country = 'USA'string = 'My name is {}, from {}, I love {}'.format(name, country, country)>>> string'My name is James, from USA, I love USA'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. Best
name = 'James'country = 'USA'string = 'My name is {name}, from {country}, I love {country}'.format(name=name, country=country)'My name is James, from USA, I love USA'# or you can simplipy it by using f-stringsname = 'James'country = 'USA'string = f'My name is {name}, from {country}, I love {country}'>>> string'My name is James, from USA, I love USA'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

使用format函數(shù)比使用%s可讀性更高,同時也更易于控制輸出格式,。

序列并包(pack)

當(dāng)你想同時訪問兩個列表的時候,,你的做法是?

  1. Bad
names = ['James', 'Tim', 'Katty']ages = [18, 19, 20]for i in range(len(names)):    print('name:', names[i],'age:', ages[i])name: James age: 18name: Tim age: 19name: Katty age: 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. Better
names = ['James', 'Tim', 'Katty']ages = [18, 19, 20]for name, age in zip(names,ages): print('name:', name,'age:', age)name: James age: 18name: Tim age: 19name: Katty age: 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

后者的方法不僅一目了然,,同時遍歷元素的行為比遍歷下標(biāo)的行為更加高效,!

序列解包(unpack)

當(dāng)你需要將一個二元組序列拆成兩列,你會怎么做,?

  1. Bad
Data = [('James', 18), ('Tim', 19), ('Katty', 20)]names, ages = [], []for name, age in Data:    names.append(name)    ages.append(age)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Better
Data = [('James', 18), ('Tim', 19), ('Katty', 20)]names = [data[0] for data in Data]ages = [data[1] for data in Data]
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  1. Best
Data = [('James', 18), ('Tim', 19), ('Katty', 20)]names, ages = zip(*Data)
  • 1
  • 2
  • 1
  • 2

zip()zip(*)是一對互逆操作,,不過需要注意,zip()zip(*)在Python 3返回的都是迭代器,,然后zip(*)通過解包返回多個元組,。

條件表達式

  1. Bad
if x<y: small=xelse: small=y
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  1. Better
small = x if x<y else y
  • 1
  • 1

后者不僅表達意思更加明了,同時代碼量也少了好幾行,。

if結(jié)構(gòu)簡化

如果你需要檢查幾個數(shù)值時:

  1. Bad
if x==1 or x==2 or x==3 or x==4: print('x =1 or 2 or 3 or 4')
  • 1
  • 2
  • 1
  • 2
  1. Better
if x in (1,2,3,4):    print('x =1 or 2 or 3 or 4')
  • 1
  • 2
  • 1
  • 2

if鏈?zhǔn)綏l件表達式

  1. Bad
if x>0 and x<10: print('0<x<10')
  • 1
  • 2
  • 1
  • 2
  1. Better
if 0<x<10:    print('0<x<10')
  • 1
  • 2
  • 1
  • 2

前者是其他語言的判斷方法,,而后者顯然更加簡潔明了。

any & all

當(dāng)存在多個條件判斷語句時:

  1. Bad
if a>0 or b>0 or c>0: print('one of them greater than 0')if a>0 and b>0 and c>0: print('all of them greater than 0')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Better
if any([a,b,c]):    print('one of them greater than 0')if all([a,b,c]):    print('all of them greater than 0')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

eval

eval函數(shù)可以輕易的將字符串轉(zhuǎn)化成元素,,甚至可以轉(zhuǎn)化表達式:

>>> eval('[1,2,3,4]')[1,2,3,4]>>> eval('(1,2,3,4)')(1,2,3,4)>>> eval('1+1')2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

eval功能可謂非常強大,,即可以做stringlisttuple,,dict之間的類型轉(zhuǎn)換,,還可以做計算器使用。它可以對能解析的字符串都做處理,,而不顧忌可能帶來的后果,!所以說eval強大的背后,是巨大的安全隱患,。
例如用戶惡意輸入下面的字符串:

open(r'D://filename.txt', 'r').read()__import__('os').system('dir')__import__('os').system('rm -rf /etc/*')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

那么eval就會不管三七二十一,,顯示你電腦目錄結(jié)構(gòu),讀取文件,,刪除文件……如果是格盤等更嚴(yán)重的操作,,它也會照做不誤。因此,,更加安全的做法是使用ast.literal_eval:

>>> ast.literal_eval('__import__('os').system('dir')')ValueError Traceback (most recent call last)<ipython-input-95-788ef7e6407f> in <module>()----> 1 ast.literal_eval('__import__('os').system('dir')')~\Anaconda3\lib\ast.py in literal_eval(node_or_string) 83 return left - right 84 raise ValueError('malformed node or string: ' + repr(node))---> 85 return _convert(node_or_string) 86 87 ~\Anaconda3\lib\ast.py in _convert(node) 82 else: 83 return left - right---> 84 raise ValueError('malformed node or string: ' + repr(node)) 85 return _convert(node_or_string) 86 ValueError: malformed node or string: <_ast.Call object at 0x000001C9DBA145F8>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

當(dāng)你試圖轉(zhuǎn)化一些'危險'的表達式時,,它會阻止你執(zhí)行并報錯。出于安全考慮,,對字符串進行類型轉(zhuǎn)換的時候最好使用ast.literal_eval

遍歷元素與下標(biāo)

當(dāng)你需要遍歷元素得同時,,獲取元素的位置下標(biāo):

  1. Bad
names = ['James', 'Tim', 'Katty']for i in range(len(names)):    print('Id:{},name:{}'.format(i,names[i]))Id:0,name:JamesId:1,name:TimId:2,name:Katty
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. Better
names = ['James', 'Tim', 'Katty']for i,name in enumerate(names): print('Id:{},name:{}'.format(i,names[i]))Id:0,name:JamesId:1,name:TimId:2,name:Katty
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

前者的代碼不僅難看,同時通過下標(biāo)訪問元素比遍歷元素效率更低,,而后者使用enumerate則優(yōu)雅高效得多,。

for/else

如果讓你判斷某個列表是否存在偶數(shù),存在則輸出該偶數(shù),,若不存在任何偶數(shù),,則輸出'There are no even Numbers'

  1. Bad
# The variable exit_even_number is redundantexit_even_number = Falsefor i in [1,3,5,7,9]:    if i%2 == 0:        print('{} is even number'.format(i))        exit_even_number = Trueif not exit_even_number:    print('There are no even Numbers')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. Better
for i in [1,3,5,7,9]: if i%2 == 0: print('{} is even number'.format(i))else: print('There are no even Numbers')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

前者多了一個exit_even_number變量,,使得代碼顯得有點臃腫,而使用后者for/else則優(yōu)雅得多,。

dict映射代替多條件查找

  1. Bad
if x == 1:    y = 100elif x == 2:    y = 200elif x ==     y = 300
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. Better
condition = {1:100, 2:200, 3:300}y = condition[x]
  • 1
  • 2
  • 1
  • 2

訪問字典元素

訪問字典元素的方法想必大家都清楚,,但是如果字典中不存在該鍵值對呢?

  1. Bad
>>> phone_number = {'James':123456,'Tim':678910,'Katty':111213 }>>> phone_number['James']123456>>> phone_number['james']KeyError                                  Traceback (most recent call last)<ipython-input-64-6f91c5f93ae0> in <module>()      1 phone_number = {'James':123456,'Tim':678910,'Katty':111213 }----> 2 phone_number['james']KeyError: 'james'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  1. Better
>>> phone_number = {'James':123456,'Tim':678910,'Katty':111213 }>>> phone_number['James'] if 'james' in phone_number else 'Not Found'123456>>> phone_number['james'] if 'james' in phone_number else 'Not Found''Not Found'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Best
>>> phone_number = {'James':123456,'Tim':678910,'Katty':111213 }>>> phone_number.get('James', 'Not Found')123456>>> phone_number.get('james', 'Not Found')'Not Found'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

defaultdict

當(dāng)你的字典中,,每一個鍵值對應(yīng)的是一個列表時,,如何使用append操作?

  1. Bad
my_dict = {}names = ['James', 'Tim', 'Katty', 'James']numbers = [123456, 678910, 111213, 456789]for name, number in zip(names, numbers): if name in my_dict: my_dict[name].append(number) else: my_dict[name] = [] my_dict[name].append(number)>>> my_dict{'James': [123456, 456789], 'Tim': [678910], 'Katty': [111213]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
from collections import defaultdictmy_dict = defaultdict(list)names = ['James', 'Tim', 'Katty', 'James']numbers = [123456, 678910, 111213, 456789]for name, number in zip(names, numbers):    my_dict[name].append(number)>>> my_dictdefaultdict(list, {'James': [123456, 456789], 'Tim': [678910], 'Katty': [111213]})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

后者使用defaultdict,,省去了判斷字典中否存在某個鍵值對應(yīng)的列表,,使得代碼更加簡潔易懂。default還有int,,tuple等類型,。
2. Better

my_dict = {}names = ['James', 'Tim', 'Katty', 'James']numbers = [123456, 678910, 111213, 456789]for name, number in zip(names, numbers): if name in my_dict: my_dict[name].append(number) else: my_dict[name] = []
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

列表/字典解析式

當(dāng)你想要生成一個列表或者字典的時候:

  1. Bad

生成列表

my_list = []for i in range(10):    my_list.append(i*i)>>> my_list[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

生成字典

my_dict = {}for i in range(10): my_dict[i]=i*i>>> my_dict{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Better

生成列表

>>> [i*i for i in range(10)][0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 1
  • 2
  • 1
  • 2

生成字典

>>> {i:i*i for i in range(10)}{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
  • 1
  • 2
  • 1
  • 2

列表/字典推導(dǎo)式是Python獨具特色的功能之一,使用可以使得你的代碼更加簡潔高效,。類似地,,你也可以使用元組推導(dǎo)式。

字符串連接

當(dāng)你需要創(chuàng)建一串字符串類似0123456789,,你會如何做,?

  1. Bad
string = ''for i in range(10):    string += str(i)>>> string'0123456789'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. Better
string = []for i in range(10): string .append(str(i))>>> ''.join(string)'0123456789'# or like thisstring = [str(i) for i in range(10)]>>> ''.join(string)'0123456789'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  1. Best
string = map(str, range(10))>>> ''.join(string)'0123456789'
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

join 是一種更加高效的字符串連接方式,使用 + 操作時,,每執(zhí)行一次 + 操作就會導(dǎo)致在內(nèi)存中生成一個新的字符串對象,,遍歷10次有10個字符串生成,造成無謂的內(nèi)存浪費,。而用 join 方法整個過程只會產(chǎn)生一個字符串對象,。最后一個方法使用了map函數(shù),在某些情況下,,map函數(shù)更易于理解,,效率更高。

'_'的妙用

在Python中,,_的作用主要用來充當(dāng)一個臨時變量,,例如:

for _ in range(5)print('Hello')
  • 1
  • 2
  • 1
  • 2

當(dāng)你只需要一個循環(huán)多次重復(fù)做某件事,但是并不需要循環(huán)體的變量,,就可以使用_當(dāng)作一個占位符代替,,同時也省去了命名的麻煩。
同時,,在Python解釋器中,,_還可以充當(dāng)一個保存臨時結(jié)果的容器:

>>> 1 + 23>>> _3
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在這里_保存了上一次解釋器運行的結(jié)果。
同時,也可以作為多變量賦值的一個承載容器:

L = [1,2,3,4,5]first, *_, last = L>>> fitst1>>> last5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

map函數(shù)

如果我們有一個函數(shù),,希望將其作用在一個list[0,1,2,3,4]上,,如何實現(xiàn)?

  1. Bad
L = []for i in [0,1, 2, 3, 4]:    L.append(f(i))>>> L[0, 1, 4, 9, 16]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Better
>>> list(map(lambda i:i*i, range(5)))[0, 1, 4, 9, 16]
  • 1
  • 2
  • 1
  • 2

后者的代碼顯然一目了然,。map接收兩個參數(shù),,一個是函數(shù),一個是序列(迭代器),,map將傳入的函數(shù)依次作用到序列(迭代器)的每個元素,并把結(jié)果作為新的迭代器返回,。同時,,作為Python內(nèi)建的高階函數(shù),事實上它把運算規(guī)則抽象了,,因此,,我們不但可以計算簡單的 f ( x ) = x 2 f(x)=x^2 f(x)=x2,還可以計算任意復(fù)雜的函數(shù),,例如作類型轉(zhuǎn)換:

>>> list(map(str, range(5)))['0', '1', '2', '3', '4']
  • 1
  • 2
  • 1
  • 2

最后很重要的一點是,,map可以接受多個迭代器序列,并且并行地對每個序列對應(yīng)元素執(zhí)行該函數(shù),,會比普通的函數(shù)更加高效,。

reduce函數(shù)

如果我們需要將[1,2,3,4]轉(zhuǎn)化成1234,如何做,?

  1. Bad
sum = 0for i in [1,2,3,4]: sum= sum*10 + i>>> sum1234
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. Better
# reduce is not built-in function from python 3from functools import reduce>>> reduce(lambda x,y: x*10+y,[1,2,3,4])1234
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在Python 3中,,reduce函數(shù)已經(jīng)不再是內(nèi)置函數(shù),而是放入了functools模塊,。reduce把一個函數(shù)作用在一個序列[x1, x2, x3…]上,,這個函數(shù)必須接收兩個參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個元素做累積計算

filter函數(shù)

當(dāng)你需要過濾一個列表的元素,,例如,,將列表中的奇數(shù)刪除,只留下偶數(shù):

L = list(range(10))for i in L: if i%2==0: L.remove(i)>>> L[0, 2, 4, 6, 8]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. Better
L = list(range(10))>>> list(filter(lambda x: x%2==0, L))[0, 2, 4, 6, 8]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

這里filter返回的是一個迭代器,,顯然后者的方法比前者更加優(yōu)雅簡潔,。

生成器(generator)

前面介紹過,我們可以直接使用列表推導(dǎo)式創(chuàng)建一個完整的列表,,當(dāng)列表元素劇增的時候,,如果只需要訪問某幾個元素,那將是十分浪費存儲空間的,。而生成器正是為了解決這一問題,,一邊循環(huán)一邊計算,列表元素按照某種算法推算出來,從而節(jié)省大量空間,。

  1. Bad
>>> [x * x for x in range(10)][0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  • 1
  • 2
  • 1
  • 2
  1. Better
>>> (x * x for x in range(10))<generator object <genexpr> at 0x000001EB028DBA98>
  • 1
  • 2
  • 1
  • 2

二者的區(qū)別只是一個用了[],,另一個用了(),前者生成一個完整的列表,,后者生成一個生成器,。生成器的作用無疑是強大的,這里不作過多介紹,,更多內(nèi)容請參加Python文檔,。

yield

寫一個簡單的斐波那契數(shù)列吧

  1. Bad
def fib(n): x, y = 0, 1 L = [] for i in range(n): L.append(y) x, y = y, x+y return L>>> fib(5)[1, 1, 2, 3, 5]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. Better
def fib(n):    x, y = 0, 1    L = []    for i in range(n):        yield y        x, y = y, x+y>>> list(fib(5))[1, 1, 2, 3, 5]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

后者使用了yield生成器,該生成器的特點是在哪里使用yield在哪里中斷,,下次返回時候從中斷處開始執(zhí)行,,并且返回的是一個生成器,從而節(jié)省空間,,提高代碼效率,。關(guān)于yield的強大之處我這里不便詳細介紹,如果你需要詳細了解,,請參見The Python yield keyword explained,。

partial函數(shù)

函數(shù)在執(zhí)行時,如果不是默認參數(shù),,就必須在調(diào)用前傳入,。但是,有些參數(shù)是可以在函數(shù)被調(diào)用之前提前獲知的,,這種情況下,,一個函數(shù)有一個或多個參數(shù)預(yù)先就能知道,以便函數(shù)能用更少的參數(shù)進行調(diào)用,。
我們先看一個乘法的例子,,讓每個傳入的參數(shù)都乘以一個固定的常數(shù):

# partial is not built-in function from python 3from functools import partialdef mul(a, b): return a*bmul_partial = partial(mul,b=10)for i in range(10): print(mul_partial(i),end=' ')# 0 10 20 30 40 50 60 70 80 90
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

也許你會說,這不就和默認參數(shù)一樣嗎,,那我只要在定義函數(shù)mul()里將b固定為10,,效果不是一樣的?

# using default parametersdef mul(a, b=10):    return a*b
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

但是,,如果你要傳入的b,,你事先并不知道,而是需要在程序運行的時候才能獲取到,,那么你如何提前使用固定參數(shù)確定好呢,?這時候partial就有著極大的用處!

lru_cache

仍然是一個計算斐波那契數(shù)列的例子,,這次我們使用遞歸實現(xiàn)(雖然遞歸效率遠低于循環(huán),,但這里只是作為一個例子演示,,實際中最好少用遞歸)

  1. Bad
import timedef fib(n): if n == 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)start = time.time()>>> fib(40)102334155>>> f'Duration: {time.time() - start}s'Duration: 40.126065492630005s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. Better
import timefrom functools import lru_cache@lru_cache(maxsize=512)def fib(n):    if n == 0: return 0    if n == 1: return 1        return fib(n-1) + fib(n-2)    start = time.time()>>> fib(40)102334155>>> f'Duration: {time.time() - start}s'Duration: 0.0009968280792236328s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以看到,使用了LRU緩存后,,二者的運行時間簡直天差地別,。

枚舉

from enum import Enum, autoclass Animal(Enum): bird = auto() dog = auto() cat = auto()>>> print(Animal.cat)Animal.cat
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Python 3 中的 Enum 類支持枚舉功能,可以使我們的程序變得更加簡潔,。 Enum 是一種便捷的變量列表的打包方式,,使用該方法能夠避免多個變量在代碼各處分布而顯得雜亂無章。枚舉是一個符號集合,,每個符號都和唯一的變量對應(yīng),。通過使用枚舉,我們可以通過符號標(biāo)識來比較各個成員,,我們還可以對枚舉本身進行迭代,。

Reference

[1] Data, what now?
[2] The Hitchhiker’s Guide to Python
[3] The Python yield keyword explained
[4] Generators

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多