*args
and **kwargs
__new__
和__init__
的區別__init__
()看兩個例子:html
a = 1 def fun(a): a = 2 fun(a) print a # 1
a = []
def fun(a): a.append(1) fun(a) print a # [1]
全部的變量均可以理解是內存中一個對象的「引用」,或者,也能夠看似c中void*的感受。前端
經過id
來看引用a
的內存地址能夠比較理解:java
a = 1 def fun(a): print "func_in",id(a) # func_in 41322472 a = 2 print "re-point",id(a), id(2) # re-point 41322448 41322448 print "func_out",id(a), id(1) # func_out 41322472 41322472 fun(a) print a # 1
注:具體的值在不一樣電腦上運行時可能不一樣。node
能夠看到,在執行完a = 2
以後,a
引用中保存的值,即內存地址發生變化,由原來1
對象的所在的地址變成了2
這個實體對象的內存地址。python
而第2個例子a
引用保存的內存值就不會發生變化:mysql
a = []
def fun(a): print "func_in",id(a) # func_in 53629256 a.append(1) print "func_out",id(a) # func_out 53629256 fun(a) print a # [1]
這裏記住的是類型是屬於對象的,而不是變量。而對象有兩種,「可更改」(mutable)與「不可更改」(immutable)對象。在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是能夠修改的對象。(這就是這個問題的重點)linux
當一個引用傳遞給函數的時候,函數自動複製一份引用,這個函數裏的引用和外邊的引用沒有半毛關係了.因此第一個例子裏函數把引用指向了一個不可變對象,當函數返回的時候,外面的引用沒半毛感受.而第二個例子就不同了,函數內的引用指向的是可變對象,對它的操做就和定位了指針地址同樣,在內存裏進行修改.nginx
若是還不明白的話,這裏有更好的解釋: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-referencegit
這個很是的不經常使用,可是像ORM這種複雜的結構仍是會須要的,詳情請看:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python程序員
Python其實有3個方法,即靜態方法(staticmethod),類方法(classmethod)和實例方法,以下:
def foo(x): print "executing foo(%s)"%(x) class A(object): def foo(self,x): print "executing foo(%s,%s)"%(self,x) @classmethod def class_foo(cls,x): print "executing class_foo(%s,%s)"%(cls,x) @staticmethod def static_foo(x): print "executing static_foo(%s)"%x a=A()
這裏先理解下函數參數裏面的self和cls.這個self和cls是對類或者實例的綁定,對於通常的函數來講咱們能夠這麼調用foo(x)
,這個函數就是最經常使用的,它的工做跟任何東西(類,實例)無關.對於實例方法,咱們知道在類裏每次定義方法的時候都須要綁定這個實例,就是foo(self, x)
,爲何要這麼作呢?由於實例方法的調用離不開實例,咱們須要把實例本身傳給函數,調用的時候是這樣的a.foo(x)
(實際上是foo(a, x)
).類方法同樣,只不過它傳遞的是類而不是實例,A.class_foo(x)
.注意這裏的self和cls能夠替換別的參數,可是python的約定是這倆,仍是不要改的好.
對於靜態方法其實和普通的方法同樣,不須要對誰進行綁定,惟一的區別是調用的時候須要使用a.static_foo(x)
或者A.static_foo(x)
來調用.
|\|實例方法|類方法|靜態方法| |:--|:--|:--|:--| |a = A()|a.foo(x)|a.class_foo(x)|a.static_foo(x)| |A|不可用|A.class_foo(x)|A.static_foo(x)|
class Person: name="aaa" p1=Person() p2=Person() p1.name="bbb" print p1.name # bbb print p2.name # aaa print Person.name # aaa
類變量就是供類使用的變量,實例變量就是供實例使用的.
這裏p1.name="bbb"
是實例調用了類變量,這其實和上面第一個問題同樣,就是函數傳參的問題,p1.name
一開始是指向的類變量name="aaa"
,可是在實例的做用域裏把類變量的引用改變了,就變成了一個實例變量,self.name再也不引用Person的類變量name了.
能夠看看下面的例子:
class Person: name=[] p1=Person() p2=Person() p1.name.append(1) print p1.name # [1] print p2.name # [1] print Person.name # [1]
參考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block
這個也是python彪悍的特性.
自省就是面向對象的語言所寫的程序在運行時,所能知道對象的類型.簡單一句就是運行時可以得到對象的類型.好比type(),dir(),getattr(),hasattr(),isinstance().
可能你見過列表推導時,卻沒有見過字典推導式,在2.7中才加入的:
d = {key: value for (key, value) in iterable}
>>> class MyClass(): ... def __init__(self): ... self.__superprivate = "Hello" ... self._semiprivate = ", world!" ... >>> mc = MyClass() >>> print mc.__superprivate Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: myClass instance has no attribute '__superprivate' >>> print mc._semiprivate , world! >>> print mc.__dict__ {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__foo__
:一種約定,Python內部的名字,用來區別其餘用戶自定義的命名,以防衝突.
_foo
:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.
__foo
:這個有真正的意義:解析器用_classname__foo
來代替這個名字,以區別和其餘類相同的命名.
或者: http://www.zhihu.com/question/19754941
.format在許多方面看起來更便利.對於%
最煩人的是它沒法同時傳遞一個變量和元組.你可能會想下面的代碼不會有什麼問題:
"hi there %s" % name
可是,若是name剛好是(1,2,3),它將會拋出一個TypeError異常.爲了保證它老是正確的,你必須這樣作:
"hi there %s" % (name,) # 提供一個單元素的數組而不是一個參數
可是有點醜..format就沒有這些問題.你給的第二個問題也是這樣,.format好看多了.
你爲何不用它?
%
(issue #4))http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format
這個是stackoverflow裏python排名第一的問題,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python
這是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html
*args
and **kwargs
用*args
和**kwargs
只是爲了方便並無強制使用它們.
當你不肯定你的函數裏將要傳遞多少參數時你能夠用*args
.例如,它能夠傳遞任意數量的參數:
>>> def print_everything(*args): for count, thing in enumerate(args): ... print '{0}. {1}'.format(count, thing) ... >>> print_everything('apple', 'banana', 'cabbage') 0. apple 1. banana 2. cabbage
類似的,**kwargs
容許你使用沒有事先定義的參數名:
>>> def table_things(**kwargs): ... for name, value in kwargs.items(): ... print '{0} = {1}'.format(name, value) ... >>> table_things(apple = 'fruit', cabbage = 'vegetable') cabbage = vegetable apple = fruit
你也能夠混着用.命名參數首先得到參數值而後全部的其餘參數都傳遞給*args
和**kwargs
.命名參數在列表的最前端.例如:
def table_things(titlestring, **kwargs)
*args
和**kwargs
能夠同時在函數的定義中,可是*args
必須在**kwargs
前面.
當調用函數時你也能夠用*
和**
語法.例如:
>>> def print_three_things(a, b, c): ... print 'a = {0}, b = {1}, c = {2}'.format(a,b,c) ... >>> mylist = ['aardvark', 'baboon', 'cat'] >>> print_three_things(*mylist) a = aardvark, b = baboon, c = cat
就像你看到的同樣,它能夠傳遞列表(或者元組)的每一項並把它們解包.注意必須與它們在函數裏的參數相吻合.固然,你也能夠在函數定義或者函數調用時用*.
http://stackoverflow.com/questions/3394835/args-and-kwargs
這個AOP一聽起來有點懵,同窗面阿里的時候就被問懵了...
裝飾器是一個很著名的設計模式,常常被用於有切面需求的場景,較爲經典的有插入日誌、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量函數中與函數功能自己無關的雷同代碼並繼續重用。歸納的講,裝飾器的做用就是爲已經存在的對象添加額外的功能。
這個問題比較大,推薦: http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python
中文: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/3/README.html
「當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就能夠被稱爲鴨子。」
咱們並不關心對象是什麼類型,究竟是不是鴨子,只關心行爲。
好比在python中,有不少file-like的東西,好比StringIO,GzipFile,socket。它們有不少相同的方法,咱們把它們看成文件使用。
又好比list.extend()方法中,咱們並不關心它的參數是否是list,只要它是可迭代的,因此它的參數能夠是list/tuple/dict/字符串/生成器等.
鴨子類型在動態語言中常用,很是靈活,使得python不想java那樣專門去弄一大堆的設計模式。
引自知乎:http://www.zhihu.com/question/20053359
函數重載主要是爲了解決兩個問題。
另外,一個基本的設計原則是,僅僅當兩個函數除了參數類型和參數個數不一樣之外,其功能是徹底相同的,此時才使用函數重載,若是兩個函數的功能其實不一樣,那麼不該當使用重載,而應當使用一個名字不一樣的函數。
好吧,那麼對於狀況 1 ,函數功能相同,可是參數類型不一樣,python 如何處理?答案是根本不須要處理,由於 python 能夠接受任何類型的參數,若是函數的功能相同,那麼不一樣的參數類型在 python 中極可能是相同的代碼,沒有必要作成兩個不一樣函數。
那麼對於狀況 2 ,函數功能相同,但參數個數不一樣,python 如何處理?你們知道,答案就是缺省參數。對那些缺乏的參數設定爲缺省參數便可解決問題。由於你假設函數功能相同,那麼那些缺乏的參數終歸是須要用的。
好了,鑑於狀況 1 跟 狀況 2 都有了解決方案,python 天然就不須要函數重載了。
這個面試官問了,我說了老半天,不知道他問的真正意圖是什麼.
這篇文章很好的介紹了新式類的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html
新式類很早在2.2就出現了,因此舊式類徹底是兼容的問題,Python3裏的類所有都是新式類.這裏有一個MRO問題能夠了解下(新式類是廣度優先,舊式類是深度優先),<Python核心編程>裏講的也不少.
__new__
和__init__
的區別這個__new__
確實不多見到,先作了解吧.
__new__
是一個靜態方法,而__init__
是一個實例方法.__new__
方法會返回一個建立的實例,而__init__
什麼都不返回.__new__
返回一個cls的實例時後面的__init__
才能被調用.__new__
,初始化一個實例時用__init__
.ps: __metaclass__
是建立類時起做用.因此咱們能夠分別使用__metaclass__
,__new__
和__init__
來分別在類建立,實例建立和實例初始化的時候作一些小手腳.
這個絕對常考啊.絕對要記住1~2個方法,當時面試官是讓手寫的.
__new__
方法class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance class MyClass(Singleton): a = 1
建立實例時把全部實例的__dict__
指向同一個字典,這樣它們具備相同的屬性和方法.
class Borg(object): _state = {} def __new__(cls, *args, **kw): ob = super(Borg, cls).__new__(cls, *args, **kw) ob.__dict__ = cls._state return ob class MyClass2(Borg): a = 1
def singleton(cls, *args, **kw): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass: ...
做爲python的模塊是自然的單例模式
# mysingleton.py class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton() # to use from mysingleton import my_singleton my_singleton.foo()
Python 中,一個變量的做用域老是由在代碼中被賦值的地方所決定的。
當 Python 遇到一個變量的話他會按照這樣的順序進行搜索:
本地做用域(Local)→當前做用域被嵌入的本地做用域(Enclosing locals)→全局/模塊做用域(Global)→內置做用域(Built-in)
線程全局鎖(Global Interpreter Lock),即Python爲了保證線程安全而採起的獨立線程運行的限制,說白了就是一個核只能在同一時間運行一個線程.
解決辦法就是多進程和下面的協程(協程也只是單CPU,可是能減少切換代價提高性能).
知乎被問到了,呵呵噠,跪了
簡單點說協程是進程和線程的升級版,進程和線程都面臨着內核態和用戶態的切換問題而耗費許多切換時間,而協程就是用戶本身控制切換的時機,再也不須要陷入系統的內核態.
Python裏最多見的yield就是協程的思想!能夠查看第九個問題.
閉包(closure)是函數式編程的重要的語法結構。閉包也是一種組織代碼的結構,它一樣提升了代碼的可重複使用性。
當一個內嵌函數引用其外部做做用域的變量,咱們就會獲得一個閉包. 總結一下,建立一個閉包必須知足如下幾點:
感受閉包仍是有難度的,幾句話是說不明白的,仍是查查相關資料.
重點是函數運行後並不會被撤銷,就像16題的instance字典同樣,當函數運行完後,instance並不被銷燬,而是繼續留在內存空間裏.這個功能相似類裏的類變量,只不過遷移到了函數上.
閉包就像個空心球同樣,你知道外面和裏面,但你不知道中間是什麼樣.
其實就是一個匿名函數,爲何叫lambda?由於和後面的函數式編程有關.
推薦: 知乎
這個須要適當的瞭解一下吧,畢竟函數式編程在Python中也作了引用.
推薦: 酷殼
python中函數式編程支持:
filter 函數的功能至關於過濾器。調用一個布爾函數bool_func
來迭代遍歷每一個seq中的元素;返回一個使bool_seq
返回值爲true的元素的序列。
>>>a = [1,2,3,4,5,6,7] >>>b = filter(lambda x: x > 5, a) >>>print b >>>[6,7]
map函數是對一個序列的每一個項依次執行函數,下面是對一個序列每一個項都乘以2:
>>> a = map(lambda x:x*2,[1,2,3]) >>> list(a) [2, 4, 6]
reduce函數是對一個序列的每一個項迭代調用函數,下面是求3的階乘:
>>> reduce(lambda x,y:x*y,range(1,4)) 6
引用和copy(),deepcopy()的區別
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始對象 b = a #賦值,傳對象的引用 c = copy.copy(a) #對象拷貝,淺拷貝 d = copy.deepcopy(a) #對象拷貝,深拷貝 a.append(5) #修改對象a a[4].append('c') #修改對象a中的['a', 'b']數組對象 print 'a = ', a print 'b = ', b print 'c = ', c print 'd = ', d 輸出結果: a = [1, 2, 3, 4, ['a', 'b', 'c'], 5] b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] c = [1, 2, 3, 4, ['a', 'b', 'c']] d = [1, 2, 3, 4, ['a', 'b']]
Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,經過「標記-清除」(mark and sweep)解決容器對象可能產生的循環引用問題,經過「分代回收」(generation collection)以空間換時間的方法提升垃圾回收效率。
PyObject是每一個對象必有的內容,其中ob_refcnt
就是作爲引用計數。當一個對象有新的引用時,它的ob_refcnt
就會增長,當引用它的對象被刪除,它的ob_refcnt
就會減小.引用計數爲0時,該對象生命就結束了。
優勢:
缺點:
基本思路是先按需分配,等到沒有空閒內存的時候從寄存器和程序棧上的引用出發,遍歷以對象爲節點、以引用爲邊構成的圖,把全部能夠訪問到的對象打上標記,而後清掃一遍內存空間,把全部沒標記的對象釋放。
分代回收的總體思想是:將系統中的全部內存塊根據其存活時間劃分爲不一樣的集合,每一個集合就成爲一個「代」,垃圾收集頻率隨着「代」的存活時間的增大而減少,存活時間一般利用通過幾回垃圾回收來度量。
Python默認定義了三代對象集合,索引數越大,對象存活時間越長。
舉例: 當某些內存塊M通過了3次垃圾收集的清洗以後還存活時,咱們就將內存塊M劃到一個集合A中去,而新分配的內存都劃分到集合B中去。當垃圾收集開始工做時,大多數狀況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔至關長一段時間後才進行,這就使得垃圾收集機制須要處理的內存少了,效率天然就提升了。在這個過程當中,集合B中的某些內存塊因爲存活時間長而會被轉移到集合A中,固然,集合A中實際上也存在一些垃圾,這些垃圾的回收會由於這種分代的機制而被延遲。
推薦: http://www.jianshu.com/p/J4U6rR
is是對比地址,==是對比值
推薦:Python 2.7.x 與 Python 3.x 的主要差別
super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.
Note that the syntax changed in Python 3.0: you can just say super().__init__
() instead of super(ChildB, self).__init__
() which IMO is quite a bit nicer.
http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods
都在循環時使用,xrange內存性能更好。 for i in range(0, 20): for i in xrange(0, 20): What is the difference between range and xrange functions in Python 2.X? range creates a list, so if you do range(1, 10000000) it creates a list in memory with 9999999 elements. xrange is a sequence object that evaluates lazily.
其實全部的I/O都是輪詢的方法,只不過實現的層面不一樣罷了.
這個問題可能有點深刻了,但相信能回答出這個問題是對I/O多路複用有很好的瞭解了.其中tornado使用的就是epoll的.
基本上select有3個缺點:
poll改善了第一個缺點
epoll改了三個缺點.
關於epoll的: http://www.cnblogs.com/my_life/articles/3968782.html
實時調度算法:
緣由:
必要條件:
處理死鎖基本方法:
推薦: http://www.ruanyifeng.com/blog/2014/11/compiler.html
Bulid過程能夠分解爲4個步驟:預處理(Prepressing), 編譯(Compilation)、彙編(Assembly)、連接(Linking)
以c語言爲例:
預編譯過程主要處理那些源文件中的以「#」開始的預編譯指令,主要處理規則有:
編譯過程就是把預處理完的文件進行一系列的詞法分析、語法分析、語義分析及優化後生成相應的彙編代碼文件。這個過程是整個程序構建的核心部分。
彙編器是將彙編代碼轉化成機器能夠執行的指令,每一條彙編語句幾乎都是一條機器指令。通過編譯、連接、彙編輸出的文件成爲目標文件(Object File)
連接的主要內容就是把各個模塊之間相互引用的部分處理好,使各個模塊能夠正確的拼接。 連接的主要過程包塊 地址和空間的分配(Address and Storage Allocation)、符號決議(Symbol Resolution)和重定位(Relocation)等步驟。
靜態連接方法:靜態連接的時候,載入代碼就會把程序會用到的動態代碼或動態代碼的地址肯定下來 靜態庫的連接可使用靜態連接,動態連接庫也可使用這種方法連接導入庫
動態連接方法:使用這種方式的程序並不在一開始就完成動態連接,而是直到真正調用動態庫代碼時,載入程序才計算(被調用的那部分)動態代碼的邏輯地址,而後等到某個時候,程序又須要調用另外某塊動態代碼時,載入程序又去計算這部分代碼的邏輯地址,因此,這種方式使程序初始化時間較短,但運行期間的性能比不上靜態連接的程序
虛擬存儲器是指具備請求調入功能和置換功能,能從邏輯上對內存容量加以擴充的一種存儲系統.
分頁: 用戶程序的地址空間被劃分紅若干固定大小的區域,稱爲「頁」,相應地,內存空間分紅若干個物理塊,頁和塊的大小相等。可將用戶程序的任一頁放在內存的任一塊中,實現了離散分配。
分段: 將用戶程序地址空間分紅若干個大小不等的段,每段能夠定義一組相對完整的邏輯信息。存儲分配時,以段爲單位,段與段在內存中能夠不相鄰接,也實現了離散分配。
邊緣觸發是指每當狀態變化時發生一個 io 事件,條件觸發是隻要知足條件就發生一個 io 事件
數據庫事務(Database Transaction) ,是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。
推薦: http://tech.meituan.com/mysql-index.html
彙集索引,非彙集索引,B-Tree,B+Tree,最左前綴原理
悲觀鎖:假定會發生併發衝突,屏蔽一切可能違反數據完整性的操做
樂觀鎖:假設不會發生併發衝突,只在提交操做時檢查是否違反數據完整性。
MyISAM 適合於一些須要大量查詢的應用,但其對於有大量寫操做並非很好。甚至你只是須要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都沒法操做直到讀操做完成。另外,MyISAM 對於 SELECT COUNT(*) 這類的計算是超快無比的。
InnoDB 的趨勢會是一個很是複雜的存儲引擎,對於一些小的應用,它會比 MyISAM 還慢。他是它支持「行鎖」 ,因而在寫操做比較多的時候,會更優秀。而且,他還支持更多的高級應用,好比:事務。
注意: 中斷鏈接端能夠是客戶端,也能夠是服務器端. 下面僅以客戶端斷開鏈接舉例, 反之亦然.
地址解析協議(Address Resolution Protocol),其基本功能爲透過目標設備的IP地址,查詢目標的MAC地址,以保證通訊的順利進行。它是IPv4網絡層必不可少的協議,不過在IPv6中已再也不適用,並被鄰居發現協議(NDP)所替代。
這個面試官確實問過,當時答的urllib2能夠Post而urllib不能夠.
GET和POST有什麼區別?及爲何網上的多數答案都是錯的 知乎回答
get: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 post: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1
Cookie | Session | |
---|---|---|
儲存位置 | 客戶端 | 服務器端 |
目的 | 跟蹤會話,也能夠保存用戶偏好設置或者保存用戶名密碼等 | 跟蹤會話 |
安全性 | 不安全 | 安全 |
session技術是要使用到cookie的,之因此出現session技術,主要是爲了安全。
nginx 相對 apache 的優勢:
apache 相對nginx 的優勢:
狀態碼 | 定義 |
---|---|
1xx 報告 | 接收到請求,繼續進程 |
2xx 成功 | 步驟成功接收,被理解,並被接受 |
3xx 重定向 | 爲了完成請求,必須採起進一步措施 |
4xx 客戶端出錯 | 請求包括錯的順序或不能完成 |
5xx 服務器出錯 | 服務器沒法完成顯然有效的請求 |
403: Forbidden 404: Not Found
HTTPS握手,對稱加密,非對稱加密,TLS/SSL,RSA
CSRF重點在請求,XSS重點在腳本
HTTP方法的冪等性是指一次和屢次請求某一個資源應該具備一樣的反作用。(注意是反作用)
GET http://www.bank.com/account/123456
,不會改變資源的狀態,不論調用一次仍是N次都沒有反作用。請注意,這裏強調的是一次和N次具備相同的反作用,而不是每次GET的結果相同。GET http://www.news.com/latest-news
這個HTTP請求可能會每次獲得不一樣的結果,但它自己並無產生任何反作用,於是是知足冪等性的。
DELETE方法用於刪除資源,有反作用,但它應該知足冪等性。好比:DELETE http://www.forum.com/article/4231
,調用一次和N次對系統產生的反作用是相同的,即刪掉id爲4231的帖子;所以,調用者能夠屢次調用或刷新頁面而沒必要擔憂引發錯誤。
POST所對應的URI並不是建立的資源自己,而是資源的接收者。好比:POST http://www.forum.com/articles
的語義是在http://www.forum.com/articles
下建立一篇帖子,HTTP響應中應包含帖子的建立狀態以及帖子的URI。兩次相同的POST請求會在服務器端建立兩份資源,它們具備不一樣的URI;因此,POST方法不具有冪等性。
PUT所對應的URI是要建立或更新的資源自己。好比:PUT http://www.forum/articles/4231
的語義是建立或更新ID爲4231的帖子。對同一URI進行屢次PUT的反作用和一次PUT是相同的;所以,PUT方法具備冪等性。
推薦: http://www.ruanyifeng.com/blog/2011/09/restful.html
SOAP(原爲Simple Object Access Protocol的首字母縮寫,即簡單對象訪問協議)是交換數據的一種協議規範,使用在計算機網絡Web服務(web service)中,交換帶結構信息。SOAP爲了簡化網頁服務器(Web Server)從XML數據庫中提取數據時,節省去格式化頁面時間,以及不一樣應用程序之間按照HTTP通訊協議,聽從XML格式執行資料互換,使其抽象於語言實現、平臺和硬件。
RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。
總結:服務提供的兩大流派.傳統意義以方法調用爲導向通稱RPC。爲了企業SOA,若干廠商聯合推出webservice,制定了wsdl接口定義,傳輸soap.當互聯網時代,臃腫SOA被簡化爲http+xml/json.可是簡化出現各類混亂。以資源爲導向,任何操做無非是對資源的增刪改查,因而統一的REST出現了.
進化的順序: RPC -> SOAP -> RESTful
CGI是通用網關接口,是鏈接web服務器和應用程序的接口,用戶經過CGI來獲取動態數據或文件等。 CGI程序是一個獨立的程序,它能夠用幾乎全部語言來寫,包括perl,c,lua,python等等。
WSGI, Web Server Gateway Interface,是Python應用程序或框架和Web服務器之間的一種接口,WSGI的其中一個目的就是讓用戶能夠用統一的語言(Python)編寫先後端。
官方說明:PEP-3333
在GFW裏家常便飯的,呵呵.
中間人攻擊(Man-in-the-middle attack,一般縮寫爲MITM)是指攻擊者與通信的兩端分別建立獨立的聯繫,並交換其所收到的數據,使通信的兩端認爲他們正在經過一個私密的鏈接與對方直接對話,但事實上整個會話都被攻擊者徹底控制。
所謂c10k問題,指的是服務器同時支持成千上萬個客戶端的問題,也就是concurrent 10 000 connection(這也是c10k這個名字的由來)。 推薦: http://www.kegel.com/c10k.html
推薦: http://www.360doc.com/content/11/0609/15/5482098_122692444.shtml
Socket=Ip address+ TCP/UDP + port
推薦: http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html
304 Not Modified
推薦: http://blog.csdn.net/elifefly/article/details/3964766
AJAX,Asynchronous JavaScript and XML(異步的 JavaScript 和 XML), 是與在不從新加載整個頁面的狀況下,與服務器交換數據並更新部分網頁的技術。
紅黑樹與AVL的比較:
AVL是嚴格平衡樹,所以在增長或者刪除節點的時候,根據不一樣狀況,旋轉的次數比紅黑樹要多;
紅黑是用非嚴格的平衡來換取增刪節點時候旋轉次數的下降;
因此簡單說,若是你的應用中,搜索的次數遠遠大於插入和刪除,那麼選擇AVL,若是搜索,插入刪除次數幾乎差很少,應該選擇RB。
一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)
第二種記憶方法
def memo(func): cache = {} def wrap(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrap @memo def fib(i): if i < 2: return 1 return fib(i-1) + fib(i-2)
第三種方法
def fib(n): a, b = 0, 1 for _ in xrange(n): a, b = b, a + b return b
一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級……它也能夠跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
fib = lambda n: n if n < 2 else 2 * fib(n - 1)
咱們能夠用2*1
的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2*1
的小矩形無重疊地覆蓋一個2*n
的大矩形,總共有多少種方法?
第
2*n
個矩形的覆蓋方法等於第2*(n-1)
加上第2*(n-2)
的方法。
f = lambda n: 1 if n < 2 else f(n - 1) + f(n - 2)
在一個m行n列二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
使用Step-wise線性搜索。
def get_value(l, r, c): return l[r][c] def find(l, x): m = len(l) - 1 n = len(l[0]) - 1 r = 0 c = n while c >= 0 and r <= m: value = get_value(l, r, c) if value == x: return True elif value > x: c = c - 1 elif value < x: r = r + 1 return False
用集合
list(set(l))
用字典
l1 = ['b','c','d','b','c','a','a'] l2 = {}.fromkeys(l1).keys() print l2
用字典並保持順序
l1 = ['b','c','d','b','c','a','a'] l2 = list(set(l1)) l2.sort(key=l1.index) print l2
列表推導式
l1 = ['b','c','d','b','c','a','a'] l2 = [] [l2.append(i) for i in l1 if not i in l2]
面試官提到的,先排序而後刪除.
1->2->3->4
轉換成2->1->4->3
.
class ListNode: def __init__(self, x): self.val = x self.next = None class Solution: # @param a ListNode # @return a ListNode def swapPairs(self, head): if head != None and head.next != None: next = head.next head.next = self.swapPairs(next.next) next.next = head return next return head
dict = {'name':'earth', 'port':'80'}
items=[('name','earth'),('port','80')] dict2=dict(items) dict1=dict((['name','earth'],['port','80']))
dict1={}.fromkeys(('x','y'),-1) dict={'x':-1,'y':-1} dict2={}.fromkeys(('x','y')) dict2={'x':None, 'y':None}
知乎遠程面試要求編程
尾遞歸
def _recursion_merge_sort2(l1, l2, tmp): if len(l1) == 0 or len(l2) == 0: tmp.extend(l1) tmp.extend(l2) return tmp else: if l1[0] < l2[0]: tmp.append(l1[0]) del l1[0] else: tmp.append(l2[0]) del l2[0] return _recursion_merge_sort2(l1, l2, tmp) def recursion_merge_sort2(l1, l2): return _recursion_merge_sort2(l1, l2, [])
循環算法
def loop_merge_sort(l1, l2): tmp = [] while len(l1) > 0 and len(l2) > 0: if l1[0] < l2[0]: tmp.append(l1[0]) del l1[0] else: tmp.append(l2[0]) del l2[0] tmp.extend(l1) tmp.extend(l2) return tmp
去哪兒的面試,沒作出來.
class ListNode: def __init__(self, x): self.val = x self.next = None def node(l1, l2): length1, lenth2 = 0, 0 # 求兩個鏈表長度 while l1.next: l1 = l1.next length1 += 1 while l2.next: l2 = l2.next length2 += 1 # 長的鏈表先走 if length1 > lenth2: for _ in range(length1 - length2): l1 = l1.next else: for _ in range(length2 - length1): l2 = l2.next while l1 and l2: if l1.next == l2.next: return l1.next else: l1 = l1.next l2 = l2.next
def binarySearch(l, t): low, high = 0, len(l) - 1 while low < high: print low, high mid = (low + high) / 2 if l[mid] > t: high = mid elif l[mid] < t: low = mid + 1 else: return mid return low if l[low] == t else False if __name__ == '__main__': l = [1, 4, 12, 45, 66, 99, 120, 444] print binarySearch(l, 12) print binarySearch(l, 1) print binarySearch(l, 13) print binarySearch(l, 444)
def qsort(seq): if seq==[]: return [] else: pivot=seq[0] lesser=qsort([x for x in seq[1:] if x<pivot]) greater=qsort([x for x in seq[1:] if x>=pivot]) return lesser+[pivot]+greater if __name__=='__main__': seq=[5,6,78,9,0,-1,2,3,-65,12] print(qsort(seq))
def coinChange(values, money, coinsUsed): #values T[1:n]數組 #valuesCounts 錢幣對應的種類數 #money 找出來的總錢數 #coinsUsed 對應於目前錢幣總數i所使用的硬幣數目 for cents in range(1, money+1): minCoins = cents #從第一個開始到money的全部狀況初始 for value in values: if value <= cents: temp = coinsUsed[cents - value] + 1 if temp < minCoins: minCoins = temp coinsUsed[cents] = minCoins print('面值爲:{0} 的最小硬幣數目爲:{1} '.format(cents, coinsUsed[cents]) ) if __name__ == '__main__': values = [ 25, 21, 10, 5, 1] money = 63 coinsUsed = {i:0 for i in range(money+1)} coinChange(values, money, coinsUsed)
給定一個數組,構建二叉樹,而且按層次打印這個二叉樹
## 14 二叉樹節點 class Node(object): def __init__(self, data, left=None, right=None): self.data = data self.left = left self.right = right tree = Node(1, Node(3, Node(7, Node(0)), Node(6)), Node(2, Node(5), Node(4))) ## 15 層次遍歷 def lookup(root): stack = [root] while stack: current = stack.pop(0) print current.data if current.left: stack.append(current.left) if current.right: stack.append(current.right) ## 16 深度遍歷 def deep(root): if not root: return print root.data deep(root.left) deep(root.right) if __name__ == '__main__': lookup(tree) deep(tree)
深度遍歷改變順序就OK了
def maxDepth(root): if not root: return 0 return max(maxDepth(root.left), maxDepth(root.right)) + 1
def isSameTree(p, q): if p == None and q == None: return True elif p and q : return p.val == q.val and isSameTree(p.left,q.left) and isSameTree(p.right,q.right) else : return False
推薦: http://blog.csdn.net/hinyunsin/article/details/6315502
def rebuild(pre, center): if not pre: return cur = Node(pre[0]) index = center.index(pre[0]) cur.left = rebuild(pre[1:index + 1], center[:index]) cur.right = rebuild(pre[index + 1:], center[index + 1:]) return cur def deep(root): if not root: return deep(root.left) deep(root.right) print root.data
class Node(object): def __init__(self, data=None, next=None): self.data = data self.next = next link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9))))))))) def rev(link): pre = link cur = link.next pre.next = None while cur: tmp = cur.next cur.next = pre pre = cur cur = tmp return pre root = rev(link) while root: print root.data root = root.next
class Anagram: """ @:param s1: The first string @:param s2: The second string @:return true or false """ def Solution1(s1,s2): alist = list(s2) pos1 = 0 stillOK = True while pos1 < len(s1) and stillOK: pos2 = 0 found = False while pos2 < len(alist) and not found: if s1[pos1] == alist[pos2]: found = True else: pos2 = pos2 + 1 if found: alist[pos2] = None else: stillOK = False pos1 = pos1 + 1 return stillOK print(Solution1('abcd','dcba')) def Solution2(s1,s2): alist1 = list(s1) alist2 = list(s2) alist1.sort() alist2.sort() pos = 0 matches = True while pos < len(s1) and matches: if alist1[pos] == alist2[pos]: pos = pos + 1 else: matches = False return matches print(Solution2('abcde','edcbg')) def Solution3(s1,s2): c1 = [0]*26 c2 = [0]*26 for i in range(len(s1)): pos = ord(s1[i])-ord('a') c1[pos] = c1[pos] + 1 for i in range(len(s2)): pos = ord(s2[i])-ord('a') c2[pos] = c2[pos] + 1 j = 0 stillOK = True while j<26 and stillOK: if c1[j] == c2[j]: j = j + 1 else: stillOK = False return stillOK print(Solution3('apple','pleap'))