怎樣才算精通Python?
- Web Programming: Django, Pyramid, Bottle, Tornado, Flask, web2py
- GUI Development: wxPython, tkInter, PyGtk, PyGObject, PyQt
- Scientific and Numeric: SciPy, Pandas, IPython
- Software Development: Buildbot, Trac, Roundup
- System Administration: Ansible, Salt, OpenStack
打個比方,如果一個工程師,要去面試一個C++的崗位,他至少會找一本C++的書認真學習,然後再去應聘。Python則不然,很多同學只花了一點點時間,了解了一下Python的語法,就說自己熟悉Python。這也導致Python的面試官相對於其他方向的面試官,更加容易遇到不合格的求職者,浪費了大家的時間。Python面試官為了不給自己找麻煩,只能提高要求,要求求職者精通Python。
怎樣才算精通Python既然精通Python本身是一件不可能的事情,而面試官又要求精通Python,作為求職者,應該達到怎樣的水平,才敢去應聘呢?我的觀點是,要求精通Python的崗位都是全職的Python開發,Python是他們的主要使用語言,要想和他們成為同事,你至少需要:1. 能夠寫出Pythonic的代碼(什麼是Pythonic的代碼,請看我在另一個問題下的回答:怎樣才能寫出pythonic的代碼? - 知乎用戶的回答)2. 對Python的一些高級特性比較熟悉3. 對Python的優缺點比較了解這樣說可能比較抽象,不太好理解。我們來看幾個例子,如果能夠充分理解這裡的每一個例子,那麼,你完全能夠順利通過"精通Python"的崗位面試。敢來挑戰嗎1.上下文管理器大家在編程的時候,經常會遇到這樣的場景:先執行一些準備操作,然後執行自己的業務邏輯,等業務邏輯完成以後,再執行一些清理操作。
比如,打開文件,處理文件內容,最後關閉文件。又如,當多線程程序需要訪問臨界資源的時候,線程首先需要獲取互斥鎖,當執行完成並準備退出臨界區的時候,需要釋放互斥鎖。對於這些情況,Python中提供了上下文管理器(Context Manager)的概念,可以通過上下文管理器來控制代碼塊執行前的準備動作以及執行後的收尾動作。我們以處理文件為例來看一下在其他語言中,是如何處理這種情況的。 Java風格/C++風格的Python代碼: myfile= open(rC:miscdata.txt)n try:n for line in myfile:n ...use line here...n finally:n myfile.close()n
with open(rC:miscdata.txt) as myfile:n for line in myfile:n ...use line here...n
- 上下文管理器管理鎖
class FetchUrls(threading.Thread):n ...n def run(self):n ...n with self.lock: #使用"with"語句管理鎖的獲取和釋放n print lock acquired by %s % self.namen print lock released by %s % self.namen
- 上下文管理器管理資料庫cursor
import pymysqlnn def get_conn(**kwargs):n return pymysql.connect(host=kwargs.get(host, localhost),n port=kwargs.get(port, 3306),n user=kwargs.get(user),n passwd=kwargs.get(passwd))nn def main():n conn = get_conn(user=laimingxing, passwd=laimingxing)n with conn as cur:n cur.execute(show databases)n print cur.fetchall()nn if __name__ == __main__:n main()n
- 上下文管理器控制運算精度
with decimal.localcontext() as ctx:n ctx.prec = 22n print(decimal.getcontext().prec)n
with open(data.txt) as source:n with open(target.txt, w) as target:n target.write(source.read())n
with open(data.txt) as source, open(target.txt, w) as target:n target.write(source.read())n
你知道上下文管理器的語法簡潔優美,寫出來的代碼不但短小,而且可讀性強。所以,作為精通Python的人,你應該能夠輕易地實現上下文管理協議。在Python中,我們就是要自己實現下面兩個協議:
你知道上下文管理器的語法簡潔優美,寫出來的代碼不但短小,而且可讀性強。所以,作為精通Python的人,你應該能夠輕易地實現上下文管理協議。在Python中,我們就是要自己實現下面兩個協議:- __enter__(self)
- __exit__(self, exception_type, exception_value, traceback)
當然,更優美的方法是使用contextmanager裝飾器。
2. 裝飾器由於我們這個問題的題目是精通Python,所以,我假設大家已經知道裝飾器是什麼,並且能夠寫簡單的裝飾器。那麼,你是否知道,寫裝飾器也有一些注意事項呢。我們來看一個例子: def is_admin(f):n def wrapper(*args, **kwargs):n if kwargs.get("username") != admin:n raise Exception("This user is not allowed to get food")n return f(*args, **kwargs)n return wrappernnn @is_adminn def barfoo(username=someone):n """Do crazy stuff"""n passnn print barfoo.func_docn print barfoo.__name__nn Nonen wrappern
import functoolsn n def is_admin(f):n @functools.wraps(f)n def wrapper(*args, **kwargs):n if kwargs.get("username") != admin:n raise Exception("This user is not allowed to get food")n return f(*arg, **kwargs)n return wrappern
import functoolsn def check_is_admin(f):n @functools.wraps(f)n def wrapper(*args, **kwargs):n if kwargs.get(username) != admin:n raise Exception("This user is not allowed to get food")n return f(*args, **kwargs)n return wrappern n @check_is_adminn def get_food(username, food=chocolate):n return "{0} get food: {1}".format(username, food)n n print get_food(admin)n
import inspectn def check_is_admin(f):n @functools.wraps(f)n def wrapper(*args, **kwargs):n func_args = inspect.getcallargs(f, *args, **kwargs)n print func_argsn if func_args.get(username) != admin:n raise Exception("This user is not allowed to get food")n return f(*args, **kwargs)n return wrappern
import sysn n import testn n a = 1n n def func1():n global an a += 1n n def func2():n test.a += 1n n def func3():n module = sys.modules[test]n module.a += 1n n func1()n func2()n func3()n
4. 時間複雜度
我們都知道,在Python裡面list是異構元素的集合,並且能夠動態增長或收縮,可以通過索引和切片訪問。那麼,又有多少人知道,list是一個數組而不是一個鏈表。關於數組和鏈表的知識,我想大家都知道了,這裡就不再贅述。如果我們在寫代碼的過程中,對於自己最常用的數據結構,連它的時間複雜度都不知道,我們又怎麼能夠寫出高效的代碼呢。寫不出高效的代碼,那我們又怎麼能夠聲稱自己精通這門編程語言呢。既然list是一個數組,那麼,我們要使用鏈表的時候,應該使用什麼數據結構呢?在寫Python代碼的時候,如果你需要一個鏈表,你應該使用標準庫collections中的deque, deque是雙向鏈表。標準庫裡面有一個queue,看起來和deque有點像,它們是什麼關係?這個問題留著讀者自己回答。我們再來看一個很實際的例子:有兩個目錄,每個目錄都有大量文件,求兩個目錄中都有的文件,此時,用Set比List快很多。因為,Set的底層實現是一個hash表,判斷一個元素是否存在於某個集合中,List的時間複雜度為O(n),Set的時間複雜度為O(1),所以這裡應該使用Set。我們應該非常清楚Python中各個常用數據結構的時間複雜度,並在實際寫代碼的過程中,充分利用不同數據結構的優勢。5. Python中的else最後我們來看一個對Python語言優缺點理解的例子,即Python中增加的兩個else。相對於C++語言或者Java語言,Python語法中多了兩個else。一個在while循環或for循環中: while True:n ....n else:n ....n
try:n ....n except:n ....n else:n ....n finally:n ....n
if <condition>n statement1n elsen statement2n
現在,我們再來看try...except語句中的else,這個else設計得特別好,其他語言也應該吸取這個設計。這個設計的語義是,執行try裡面的語句,這裡面的語句可能會出現異常,如果出現了異常,就執行except裡面的語句,如果沒有出現異常,就執行else裡面的語句,最後,無論是否出現異常,都要執行finally語句。這個設計好就好在,else的語句完全和我們的直觀感受是一樣的,是在沒有出現異常的情況下執行。並且,有else比沒有else好,有了else以後,正確地將程序員認為可能出現異常的代碼和不可能出現異常的代碼分開,這樣,更加清楚的表明了是哪一條語句可能會出現異常,更多的暴露了程序員的意圖,使得代碼維護和修改更加容易。
結論:我這篇回答很長,但是,我相信對很多人都會有幫助。這裡想說的是,Python是一門編程語言,使用範圍非常廣泛,大家不要去追求精通Python程序語言自身,而應該將精力放在自己需要解決的實際問題上。其次,絕大多數人對Python的認識都存在誤區,認為Python很簡單,只是簡單地了解一下就開始寫Python代碼,寫出了一堆很不好維護的代碼,我希望這一部分人看到我的回答以後,能夠回去重新學習Python。最後,對於一些同學的疑慮——招聘職位要求精通Python,我的回答是,他們並不奢望招到一個精通Python的人,他們只是想招到一個合格的工程師,而大部分的Python工程師,都,不,合,格!推薦閱讀:
TAG:Python |