<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          6個Python酷技巧,原來還能這樣用!

          共 7096字,需瀏覽 15分鐘

           ·

          2020-09-27 14:37



          0
          引言


          不管學(xué)什么,我個人是非常喜歡小技巧(tricks)的,Python 也不例外。著名 Python 技巧大師 Dan Bader 是這樣定義 Python Tricks 的。


          A?Python?Trick?either?teaches?an?aspect?of?Python?with?a?simple?illustration,?or?it?serves?as?a?motivating?example,?enabling?you?to?dig?deeper?and?develop?an?intuitive?understanding.

          Dan Bader

          Python Trick 表現(xiàn)簡單而直觀,但可以激發(fā)你繼續(xù)深挖的興趣,你會說“原來還可以這樣做啊”。


          今天就來介紹6個我最喜歡的 Trick,使用它們可以讓你的代碼更 Pythonic:


          1. 下劃線占位符

          2. 枚舉

          3. 打包

          4. 解包

          5. 動態(tài)屬性

          6. 密碼函數(shù)


          它們都非常直觀而簡單,相信讀完之后,肯定有幾個技巧會讓你驚嘆到,原來 Python 還可以這么用。





          1
          下劃線占位符


          有時候數(shù)字一大,數(shù)起來會犯迷糊,看下例。

          apple_mktcap?=?1084000000000facebook_mktcap?=?458870000000total = apple_mktcap + facebook_mktcapprint(total)
          1542870000000.0


          這個蘋果和臉書的市值之和有多少個零???數(shù)不清楚是吧,在 Python 中,我們可以用下劃線占位符(underscore placeholder)來將大數(shù)每三位數(shù)分段。請注意,多加了下劃線,數(shù)字還是數(shù)值型變量,只是讓我們?nèi)菀妆嬲J(rèn)大數(shù)。

          apple_mktcap = 1_084_000_000_000facebook_mktcap = 458_870_000_000total = apple_mktcap + facebook_mktcapprint(total)
          1542870000000


          你看,加個下劃線的數(shù)字還是可以相加,但是結(jié)果還是不好認(rèn)。還記得 f string 格式化字符串嗎?用 :, 來每三位數(shù)分段。

          print(f'Total is {total:,} USD')
          Total is?1,542,870,000,000?USD



          “下劃線占位符”解決痛點(diǎn):容易辨認(rèn)大數(shù)的位數(shù)。






          2
          枚舉


          給定一列表,包含四種計算機(jī)語言的元素。

          languages = ['Python', 'R', 'Matlab', 'Julia']


          如果我們想把每中語言附加對應(yīng)的索引一來打印出來,怎么寫代碼呢?最直接的想法就是初始化 index 為 0,然后在運(yùn)行每個 for 循環(huán)后將 index 的值加 1,代碼如下。?

          index = 0for lang in languages:    print(index, lang)    index +=1
          0 Python
          1 R
          2 Matlab
          3 Julia


          結(jié)果是對的,但是這代碼你不覺得很丑嗎?很不 Pythonic 嗎?


          Python 有 enumerate() 函數(shù)可以一次性返回列表(任意迭代器)的元素以及其對應(yīng)的索引,代碼如下,優(yōu)雅嗎?

          for index, lang in enumerate(languages):    print(index, lang)
          0 Python
          1 R
          2 Matlab
          3 Julia


          除此之外,你還可以自定義索引的初始值。在實(shí)際生活中,一般索引從 1 開始更自然,那么將參數(shù) start 設(shè)置為 1 就好了。

          for index, lang in enumerate(languages, start=1):    print(index, lang)
          1 Python
          2 R
          3 Matlab
          4 Julia



          “枚舉函數(shù) enumerate()”解決痛點(diǎn)不需要顯性創(chuàng)建索引。





          3
          打包


          給定一串名字(names)和演員角色(actors),用兩個列表存儲。

          names = ['小羅伯特唐尼', '托比·馬奎爾', '克里斯蒂安·貝爾', '杰森·莫瑪']actors = ['鋼鐵俠', '蜘蛛俠', '蝙蝠俠', '水行俠']


          如果我們想把每個名字和角色一一對應(yīng)起來,可以用上節(jié)學(xué)到的?enumerate() 函數(shù)。我們可以返回 names 里的元素和索引,再用索引來獲取 actors 里的元素,代碼如下。

          for index, name in enumerate(names):    print(f'{name}是{actors[index]}')
          小羅伯特唐尼是鋼鐵俠
          托比·馬奎爾是蜘蛛俠
          克里斯蒂安·貝爾是蝙蝠俠
          杰森·莫瑪是水行俠


          結(jié)果是對的,但是代碼不夠優(yōu)雅。來,zip() 函數(shù)了解一下?

          for name, actor in zip(names, actors):    print(f'{name}是{actor}')
          小羅伯特唐尼是鋼鐵俠
          托比·馬奎爾是蜘蛛俠
          克里斯蒂安·貝爾是蝙蝠俠
          杰森·莫瑪是水行俠


          zip()?函數(shù)將列表(迭代器)中對應(yīng)的元素打包成一個個元組,然后返回由這些元組組成的列表。上面代碼是不是漂亮多了。


          再加一個列表如何?zip() 函數(shù)表示毫無壓力。

          universes = ['漫威', '漫威', 'DC', 'DC']
          for name, actor, universe in zip(names, actors, universes):    print(f'{name}是來自{universe}的{actor}')
          小羅伯特唐尼是來自漫威的鋼鐵俠
          托比·馬奎爾是來自漫威的蜘蛛俠
          克里斯蒂安·貝爾是來自DC的蝙蝠俠
          杰森·莫瑪是來自DC的水行俠



          讓我們再看一次?zip() 函數(shù)的用法,其 3 個參數(shù) names, actors 和 universes 列表中都有 4 個元素,那么在對應(yīng)的位置 i(從 0 到 3)一個個獲取 names[i], actors[i] 和 universes[i],并打包成新列表,因此輸出是 4 個列表,每個列表有 3 個元素。

          a = zip(names, actors, universes)print(*a)
          ('小羅伯特唐尼', '鋼鐵俠', '漫威')
          ('托比·馬奎爾', '蜘蛛俠', '漫威')
          ('克里斯蒂安·貝爾', '蝙蝠俠', 'DC')
          ('杰森·莫瑪', '水行俠', 'DC')


          結(jié)果沒問題。需要注意的是 a 實(shí)際上是個對象,要看它里面的內(nèi)容,需要在 a 前面加個?* 字符。


          你們現(xiàn)在肯定會想,有了?zip(),那有沒有其反向操作的?unzip() 呢?答案是沒有,zip() 的反向操作還是 .... zip()!!!


          你品,你細(xì)品。

          a = zip(names, actors, universes)names, actors, universes = zip(*a)print(names, actors, universes)
          ('小羅伯特唐尼', '托比·馬奎爾', '克里斯蒂安·貝爾', '杰森·莫瑪')
          ('鋼鐵俠', '蜘蛛俠', '蝙蝠俠', '水行俠')
          ('漫威', '漫威', 'DC', 'DC')



          “打包函數(shù) zip()”解決痛點(diǎn):能同時遍歷多個迭代器。






          4
          解包


          一個簡單例子,將 1 和 2 分別賦給 a 和 b,這種操作稱為解包(unpack)。

          a, b = 1, 2print(a)print(b)
          1
          2



          如果你不想要 b 的話,用下劃線代替就行了。

          a, _ = 1, 2print(a)
          1



          但如果等號左右兩邊元素和變量個數(shù)不一樣。程序會報錯。

          a, b, c = 1, 2
          ---------------------------------------------------------------------------
          ValueError Traceback (most recent call?last)
          input-77-9dbc59cfd6c6> in?<module>
          ----> 1 a, b, c = 1, 2

          ValueError: not?enough values?to?unpack (expected 3, got 2)



          用 * 字符可以解決這個問題。將右邊的 1 和 2 分別解包給 a 和 b,那么什么都不剩了,因此 c 得到的是個空集 []。

          a, b, *c = 1, 2print(a)print(b)print(c)
          1
          2
          []



          如果右邊元素多過左邊變量呢?從頭開始一一解包,再把多余的全部賦給 c。

          a, b, *c = 1, 2, 3, 4, 5print(a)print(b)print(c)
          1
          2
          [3, 4, 5]



          更進(jìn)一步,我們還可以從頭和尾開始一一解包,再把多余的全部賦給 c。

          a, b, *c, d = 1, 2, 3, 4, 5print(a)print(b)print(c)print(d)
          1
          2
          [3, 4]
          5



          不想要 c 的話,用 *_??將其代替即可。

          a, b, *_, d = 1, 2, 3, 4, 5print(a)print(b)print(d)
          1
          2
          5


          “解包”解決痛點(diǎn):將值賦給正確的變量。





          5
          動態(tài)屬性


          這個技巧是我覺得最有用的。首先定一個金融產(chǎn)品的類 Instrument,并創(chuàng)建一個對象 inst。

          class Instrument():    pass
          inst = Instrument()


          定義 inst 的兩個屬性并賦值,本金(notional)和到期日(maturity)。

          inst.notional = 100_000_000inst.maturity = '2025-03-25'
          print(inst.notional)print(inst.maturity)
          100000000
          2025-03-25


          現(xiàn)在將屬性 notional 和其屬性值 10000000 存儲在變量 first_key 和 first_val 中。

          first_key = 'notional'first_val = 100_000_000


          我們想用 first_key 的值 notional(而不是 first_key 這個字符)來作為屬性。

          inst = Instrument()inst.first_key = first_val


          打印 inst.notional 會報錯,錯誤是 Instrument 對象中沒有 notional 這樣的屬性名。

          print(inst.notional)
          ---------------------------------------------------------------------------
          AttributeError Traceback (most recent call?last)
          input-99-50eeb1451324> in?<module>
          ----> 1 print(inst.notional)

          AttributeError: 'Instrument'?object?has no?attribute?'notional'



          原因是 inst 把 first_key 這個字符串當(dāng)成屬性名,驗(yàn)證如下。

          print(inst.first_key)
          100000000



          怎么解決這個動態(tài)屬性的問題呢?即我們要變量的值為屬性名,而不是變量本身名稱當(dāng)屬性名。用 setattr() 函數(shù),它有三個參數(shù):


          • 參數(shù) 1 - 對象

          • 參數(shù) 2 - 屬性名的變量名

          • 參數(shù) 3?- 屬性值的變量名


          代碼如下,這時用 inst.notional 不會報錯了。

          inst = Instrument()setattr(inst, first_key, first_val)print(inst.notional)
          100000000



          setattr() 相對應(yīng),你可以用 getattr() 函數(shù)來獲取屬性值,它有兩個參數(shù):


          • 參數(shù) 1 - 對象

          • 參數(shù) 2 - 屬性名的變量名


          代碼如下:

          getattr(inst, first_key)
          100000000



          和靜態(tài)屬性相比,動態(tài)屬性到底好在哪里呢?以讀取歐式期權(quán)的特征舉例,通常信息以字典(也有其他格式)存儲,具體內(nèi)容如下:

          inst_info = {'ID':'9001001', ?????????????'Effective?Date':'2020-03-20',??????????????'Maturity?Date':'2020-06-20',?????????????'Notional':10_000_000,?????????????'Domestic?Currency':'USD',?????????????'Foreign?Currency':'EUR',?????????????'Flavor':'Put',?????????????'Strike':1.08,?????????????'Display':'domestic?pips',?????????????'Asset?Class':'FX',?????????????'Ins trument?Type':'European?Option',             'Model':'Heston'}


          那么當(dāng)我們創(chuàng)建 inst 對象時,把上面字典的鍵(key)作為屬性名。每種產(chǎn)品具體的特征都不一樣,如果用靜態(tài)屬性的將字典轉(zhuǎn)成對象的話,代碼會非常亂而且無法管理,但如果用動態(tài)屬性的話,下面三行代碼就能搞定(用 setattr())。

          inst = Instrument()for key, val in inst_info.items():    setattr(inst, key, val)


          getattr()?函數(shù)來打印出來看結(jié)果對不對,兩行代碼搞定。

          for key in inst_info.keys():    print( key, '|', getattr(inst, key))
          ID | 9001001
          Effective Date |
          ?2020-03-20
          Maturity Date | 2020-06-20
          Notional |
          ?10000000
          Domestic Currency | USD
          Foreign Currency |
          ?EUR
          Flavor | Put
          Strike |
          ?1.08
          Display | domestic pips
          Asset Class |
          ?FX
          Instrument Type | European Option
          Model |
          ?Heston



          結(jié)果是對的,但也是丑的,用 f string 來添加若干個空白,將每個屬性值的起始位置對齊。

          for key in inst_info.keys():    print( f'{key:18s}|', getattr(inst, key))
          ID | 9001001
          Effective Date |
          ?2020-03-20
          Maturity Date | 2020-06-20
          Notional |
          ?10000000
          Domestic Currency | USD
          Foreign Currency |
          ?EUR
          Flavor | Put
          Strike |
          ?1.08
          Display | domestic pips
          Asset Class |
          ?FX
          Instrument Type | European Option
          Model |
          ?Heston



          “動態(tài)屬性 setattr()”解決痛點(diǎn):用盡可能少的代碼快速創(chuàng)建對象。





          6
          密碼函數(shù)


          當(dāng)?shù)卿洉r,你需要輸入你的用戶名和密碼,用 input() 函數(shù)可以做到要求用戶主動輸入,但是輸入的密碼任何人都可見,這還是密碼嗎?

          username = input('Username: ')password = input('Password: ')print('Logging In...')

          Username: Steven
          Password: 1031
          Logging In ...



          getpass() 函數(shù)即可,不解釋,自己看下圖。

          from getpass import getpassusername = input('Username: ')password = getpass('Password: ')print('Logging In...')

          Username: Steven
          Password: ········
          Logging In ...



          “密碼函數(shù) getpass()”解決痛點(diǎn):讓輸入的密碼不可見。





          7
          總結(jié)


          六個小技巧,簡單直觀,但是超級有用。有時候就是用這樣的一個函數(shù),你不知道,寫出來的代碼不優(yōu)雅;你知道了,寫出來的代碼真好看。


          六個技巧總結(jié)如下:


          • 下劃線占位符:容易辨認(rèn)大數(shù)的位數(shù)

          • 枚舉函數(shù)?enumerate()不需要顯性創(chuàng)建索引

          • 打包函數(shù)?zip():能同時遍歷多個迭代器

          • 解包將值賦給正確的變量

          • 動態(tài)屬性?setattr():用盡可能少的代碼快速創(chuàng)建對象

          • 密碼函數(shù)?getpass():讓輸入的密碼不可見


          用起來,酷起來。


          作者:王圣元
          來源:王的機(jī)器


          _往期文章推薦_

          一行Python代碼能實(shí)現(xiàn)什么奇葩功能?




          瀏覽 63
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产综合福利在线 | 亚洲欧洲日本不卡视频在线观看 | 一级黄色日皮 | 久久久大学生毛片 | 色婷婷激情五月天 |