用 Python 時間也算不短了,但總感受本身在用寫 C++ 代碼的思惟寫 Python,沒有真正用到其做爲腳本語言的優點。以前刷 LeetCode 時,本身的 Python 代碼老是很長,很像披着 Python 外衣的 C++ 代碼(放在這裏,不斷重構中)。python
想來大概是由於以爲python簡單,平時只是零零碎碎的學習,也沒有去讀別人的代碼,致使掌握的不夠深刻。回想起前段時間的面試,面試官看我簡歷寫熟悉Python,就問了兩個Python的問題:git
Python 中經常使用的優化技巧(可以提高 Python 執行效率的,除了算法層面)github
按照 value 從小到大輸出 dict 中的 key-value值。web
我支支吾吾半天,就是沒有答到點上,直接致使被拒(後來整理的內容放在這裏)。所謂知恥然後勇,通過一段時間對 Python 的從新學習,才慢慢發現 Python 的一些強大與美妙之處。面試
程序中常常用到排序函數,Python 提供了 sort 和 sorted 函數,一個原地排序,一個返回排序後的新結果,函數原型很簡單:算法
sort([cmp[, key[, reverse]]])
本身用的最多的相似下面的語句:編程
>>> l = [43, 12, 4, 6] >>> l.sort() >>> l [4, 6, 12, 43]
曾經竊覺得這就體現了 Python 的簡單優雅,不像 C++ STL中那樣還須要指定迭代器範圍,而後對 sort 的理解也就止步於此。後來遇到稍微複雜一點的排序場景,本身就 Google-Stackoverflow-Copy,解決了眼前的問題,可是歷來沒有去深挖(這也就致使那次面試中中沒有回答出來上面的第二個問題)。segmentfault
後來去看了下 sort 的函數說明,包括 cmp, key, reverse 參數究竟怎麼去用,又寫了幾個例子,覺得這下子對 sort 可謂是理解透徹了。好比要要根據值的大小輸出字典內容,那麼就能夠像下面這樣優雅地解決:網絡
>>> d = {1: 'z', 2:'y', 3: 'x'} >>> print sorted(d.items(), key=lambda x: x[1]) [(3, 'x'), (2, 'y'), (1, 'z')]
我甚至能夠獲得一個根據value排序的字典,只須要用 collections.OrderedDict
便可:數據結構
>>> from collections import OrderedDict >>> sorted_d = OrderedDict(sorted(d.items(), key=lambda x: x[1])) >>> sorted_d OrderedDict([(3, 'x'), (2, 'y'), (1, 'z')])
我覺得我對 sort 理解足夠了,直到在 hackerrank 遇到這個題目。
給定一個只包含大小寫字母,數字的字符串,對其進行排序,保證:
全部的小寫字母在大寫字母前面
全部的字母在數字前面
全部的奇數在偶數前面
考慮用 sort 函數來完成排序。開始以前,再來看看文檔對sort函數中key的說明:
key parameter to specify a function to be called on each list element prior to making comparisons. The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.
通俗講,key 用來決定在排序算法中 cmp 比較的內容,key 能夠是任何可被比較的內容,好比元組(python 中元組是可被比較的)。因此上面的排序問題能夠用下面的代碼來解決:
>>> s = "Sorting1234" >>> "".join(sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))) 'ginortS1324'
這裏,lambda 函數將輸入的字符轉換爲一個元組,而後 sorted 函數將根據元組
(而不是字符)來進行比較,進而判斷每一個字符的先後順序。
若是一樣的程序用 C++ 來寫的話,可能須要一個複雜的仿函數,來定義排序的規則,遠沒有 Python 這般簡潔優雅。
Python 是一門簡單方便的語言,相信這是大部分人對 Python 的第一感受。初學 Python,咱們可能癡迷於 Python 的列表解析,list 切片,字典推導,或者是陶醉在各類強大的第三方庫裏,好比網絡庫 requests,科學計算庫 numpy,web開發框架 Django 等。
可是實際寫程序中,咱們常常會寫出許多繁雜的、醜陋的
Python代碼。好比要判斷一個數字是不是迴文數字,可能會習慣性地寫出下面這樣的代碼:
def isPalindrome(x): if x < 0: return False reversed_x = 0 original_x = x while x > 0: reversed_x = reversed_x * 10 + x % 10 x /= 10 return reversed_x == original_x
仔細一看,這簡直就是 C++ 代碼,徹底沒有 Python 的優雅與簡單。那麼,該怎樣寫纔可以顯的 Pythonic 呢?其實,用 Python 的話只要一行就能夠啦(這裏不考慮效率,若是考慮效率的話,C++會更加合適,單對這題來講,其實有比上面更高效的方法)!
def isPalindrome(x): return x >= 0 and str(x) == str(x)[::-1]
那麼如何養成用 Pythonic 的思惟解決問題呢?我以爲首先要對 Python 十分熟悉,精通大部分函數以及 Python 的特點:好比裝飾器,迭代器,生成器以等,下面舉幾個簡單的例子:
# 函數式編程 >>> nums = map(int, "123456789" ) >>> nums [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 15 >>> sum(nums) 45 # 生成器 >>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print i ... 0 1 4 >>> for i in mygenerator: ... print i ... # lambda 匿名函數 >>> c = lambda *z: z >>> c( 10, 'test') (10, 'test') # 迭代 >>> l = [i**2 for i in range(9)] >>> l_iter = iter(l) >>> next(l_iter) 0 >>> next(l_iter) 1 >>> next(l_iter) 4 # 數據結構 set >>> set_a = set([i for i in range(1,9,2)]) >>> set_b = set([i for i in range(0,9,2)]) >>> print set_a | set_b set([0, 1, 2, 3, 4, 5, 6, 7, 8])
其次,要多讀一些 Pythonic 的代碼,學習別人如何優雅地使用python。這裏我推薦去看 Leetcode 的 Discuss,裏面有許多驚才豔豔的代碼。特別推薦 @StefanPochmann,許多代碼讓我獲益匪淺,好比這裏對 iter() 的使用。
再來看一個問題,按照二進制位反轉 32 位的一個整形無符號數字。用 Python 能夠寫出很簡單直觀的代碼,以下:
def reverseBits(n): bit_str = '{0:032b}'.format(n) reverse_str = bit_str[::-1] return int(reverse_str, 2)
固然,上面不考慮效率,這裏有一個利用分治法思想的高效的方法。
Python 是一門高效、簡單、方便的語言,但這並不意味你不花時間就能夠用的很好。
Sorting Mini-HOW TO
sort()中cmp參數的用法
hackerrank: ginortS
Sort a Python dictionary by value
Python高級編程技巧