面試題(github+自己整合的纬纪,僅供學(xué)習(xí)交流))


Table of Contents

Python語言特性

1 對(duì)Python的理解(對(duì)比其他語言)

下面是一些關(guān)鍵點(diǎn):

  • Python是一種解釋型語言衷蜓。這就是說累提,與C語言和C的衍生語言不同,Python代碼在運(yùn)行之前不需要編譯磁浇。
  • Python是動(dòng)態(tài)類型語言斋陪,指的是你在聲明變量時(shí),不需要說明變量的類型置吓。
  • Python非常適合面向?qū)ο蟮木幊蹋∣OP)无虚,因?yàn)樗С滞ㄟ^組合(composition)與繼承(inheritance)的方式定義類(class)。
  • Python中沒有訪問說明符(access specifier衍锚,類似C++中的public和private)友题,這么設(shè)計(jì)的依據(jù)是“大家都是成年人了”。

在Python語言中戴质,函數(shù)是第一類對(duì)象(first-class objects)度宦。這指的是它們可以被指定給變量,函數(shù)既能返回函數(shù)類型告匠,也可以接受函數(shù)作為輸入戈抄。類(class)也是第一類對(duì)象。
Python代碼編寫快凫海,但是運(yùn)行速度比編譯語言通常要慢呛凶。好在Python允許加入基于C語言編寫的擴(kuò)展,因此我們能夠優(yōu)化代碼行贪,消除瓶頸漾稀,這點(diǎn)通常是可以實(shí)現(xiàn)的。numpy就是一個(gè)很好地例子建瘫,它的運(yùn)行速度真的非痴负矗快,因?yàn)楹芏嗨阈g(shù)運(yùn)算其實(shí)并不是通過Python實(shí)現(xiàn)的啰脚。

Python用途非常廣泛——網(wǎng)絡(luò)應(yīng)用殷蛇,自動(dòng)化,科學(xué)建模橄浓,大數(shù)據(jù)應(yīng)用粒梦,等等。它也常被用作“膠水語言”荸实,幫助其他語言和組件改善運(yùn)行狀況匀们。
Python讓困難的事情變得容易,因此程序員可以專注于算法和數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)准给,而不用處理底層的細(xì)節(jié)泄朴。

補(bǔ)充

  • Python彩蛋
import this

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!

import __hello__

Hello world!

2 什么是Python的命名空間

在Python中重抖,所有的名字都存在于一個(gè)空間中,它們?cè)谠摽臻g中存在和被操作——這就是命名空間祖灰。

它就好像一個(gè)盒子钟沛,每一個(gè)變量名字都對(duì)應(yīng)裝著一個(gè)對(duì)象。當(dāng)查詢變量的時(shí)候局扶,會(huì)從該盒子里面尋找相應(yīng)的對(duì)象恨统。

3 Python中的pass語句

Pass是一個(gè)在Python中不會(huì)被執(zhí)行的語句。在復(fù)雜語句中详民,如果一個(gè)地方需要暫時(shí)被留白延欠,它常常被用于占位符。

4 Python異常處理的用法和作用

[參考廖雪峰](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191375461417a222c54b7e4d65b258f491c093a515000]
答:try…except…except…[else…][finally…)

  • 執(zhí)行try下的語句沈跨,如果引發(fā)異常,則執(zhí)行過程會(huì)跳到except語句兔综。對(duì)每個(gè)except分支順序嘗試執(zhí)行饿凛,如果引發(fā)的異常與except中的異常組匹配,執(zhí)行相應(yīng)的語句软驰。

  • 如果所有的except都不匹配涧窒,則異常會(huì)傳遞到下一個(gè)調(diào)用本代碼的最高層try代碼中。

  • try下的語句正常執(zhí)行锭亏,則執(zhí)行else塊代碼纠吴。如果發(fā)生異常,就不會(huì)執(zhí)行

  • 如果存在finally語句慧瘤,最后總是會(huì)執(zhí)行戴已。

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

5 Python的函數(shù)參數(shù)傳遞

看兩個(gè)例子:

a = 1
def fun(a):
    a = 2
fun(a)
print a  # 1
a = []
def fun(a):
    a.append(1)
fun(a)
print a  # [1]

所有的變量都可以理解是內(nèi)存中一個(gè)對(duì)象的“引用”

通過id來看引用a的內(nèi)存地址可以比較理解:

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

注:具體的值在不同電腦上運(yùn)行時(shí)可能不同。

可以看到锅减,在執(zhí)行完a = 2之后糖儡,a引用中保存的值,即內(nèi)存地址發(fā)生變化怔匣,由原來1對(duì)象的所在的地址變成了2這個(gè)實(shí)體對(duì)象的內(nèi)存地址握联。

而第2個(gè)例子a引用保存的內(nèi)存值就不會(huì)發(fā)生變化:

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]

這里記住的是類型是屬于對(duì)象的,而不是變量每瞒。而對(duì)象有兩種,“可變”(mutable)與“不可變”(immutable)對(duì)象金闽。在python中,string, tuple, 和number是不可更改的對(duì)象剿骨,而 list, dict, set 等則是可以修改的對(duì)象代芜。(這就是這個(gè)問題的重點(diǎn))

當(dāng)一個(gè)引用傳遞給函數(shù)的時(shí)候,函數(shù)自動(dòng)復(fù)制一份引用,這個(gè)函數(shù)里的引用和外邊的引用沒有半毛關(guān)系了.所以第一個(gè)例子里函數(shù)把引用指向了一個(gè)不可變對(duì)象,當(dāng)函數(shù)返回的時(shí)候,外面的引用沒半毛感覺.而第二個(gè)例子就不一樣了,函數(shù)內(nèi)的引用指向的是可變對(duì)象,對(duì)它的操作就和定位了指針地址一樣,在內(nèi)存里進(jìn)行修改.

如果還不明白的話,這里有更好的解釋: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference

6 函數(shù)的參數(shù)用法和注意事項(xiàng)

(參考廖雪峰課程)[https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000]
函數(shù)參數(shù)分為位置參數(shù)、默認(rèn)參數(shù)懦砂、可變參數(shù)蜒犯、關(guān)鍵字參數(shù)组橄、命名關(guān)鍵字參數(shù)(定義和調(diào)用必須按順序傳入)

numbers=[1,2,3,4,5]
def sum(*args):
    sum=0
    for i in args:
        sum = sum+i*i
    return sum  
sum(*numbers)

dict1={'a':1,'b':2}
def f(**kwargs):
    for k,v in kwargs.items():
        print('{0}:{1}'.format(k,v))
f(**dict1)

# 如果需要約束傳入的關(guān)鍵字參數(shù)的名稱,可以用命名關(guān)鍵字參數(shù)
# 命名關(guān)鍵字參數(shù)必須傳入?yún)?shù)名罚随,這和位置參數(shù)不同玉工。
def person(name, age, *, city, job):
    print(name, age, city, job)

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

# 命名關(guān)鍵字參數(shù)可以有缺省值,從而簡(jiǎn)化調(diào)用:
def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

7 可變對(duì)象和不可變對(duì)象

  • python所有數(shù)字類型(布爾樹,整數(shù),浮點(diǎn)數(shù),復(fù)數(shù))均為不可變對(duì)象,
  • 可變對(duì)象:file,dict,set,list,bytesarray,range
  • 不可變對(duì)象:boolean,int,float,complex,tuple,str,bytes,frozenset
  • 有序sequence:str,list,tuple,OrderedDict,
  • 無序:dict,set,
  • 不可重復(fù):set,tuple
  • 可變對(duì)象(mutable object)has no hash value
  • 不可變對(duì)象可哈希,hashable

8 def是運(yùn)行時(shí)執(zhí)行語句,并且是賦值語句

類和對(duì)象均為第一類對(duì)象淘菩,調(diào)用的時(shí)候才會(huì)運(yùn)行

9 Python是否能以可變對(duì)象做函數(shù)默認(rèn)參數(shù)

不可以,字典,集合,列表等可變對(duì)象不適合作為函數(shù)默認(rèn)值
要不然第二次調(diào)用時(shí),一次調(diào)用的默認(rèn)參數(shù)的值會(huì)影響二次調(diào)用.

def f(l=[]):
    for i in range(3):
        l.append(i)
    return l
f(l=[2]),---- l=[2,0,1,2]
f(),     ---- l=[0,1,2]
f(),     ---- l=[0,1,2,0,1,2]

10 企圖在函數(shù)中修改全局變量,沒有使用global,而創(chuàng)建了本地變量

修改全局變量需要global聲明,要不然會(huì)創(chuàng)建同名的本地變量.

11 對(duì)象的dir屬性和dict屬性

Python一切皆對(duì)象遵班,每個(gè)對(duì)象都有自己獨(dú)特的屬性和方法
dir()函數(shù)會(huì)自動(dòng)尋找一個(gè)對(duì)象的所有屬性,包括dict中的屬性潮改。
dict是dir()的子集狭郑,dir()包含dict中的屬性。

12 @staticmethod和@classmethod

Python其實(shí)有3個(gè)方法,即靜態(tài)方法(staticmethod),類方法(classmethod)和實(shí)例方法,如下:

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()

這里先理解下函數(shù)參數(shù)里面的self和cls.這個(gè)self和cls是對(duì)類或者實(shí)例的綁定,對(duì)于一般的函數(shù)來說我們可以這么調(diào)用foo(x),這個(gè)函數(shù)就是最常用的,它的工作跟任何東西(類,實(shí)例)無關(guān).對(duì)于實(shí)例方法,我們知道在類里每次定義方法的時(shí)候都需要綁定這個(gè)實(shí)例,就是foo(self, x),為什么要這么做呢?因?yàn)閷?shí)例方法的調(diào)用離不開實(shí)例,我們需要把實(shí)例自己傳給函數(shù),調(diào)用的時(shí)候是這樣的a.foo(x)(其實(shí)是foo(a, x)).類方法一樣,只不過它傳遞的是類而不是實(shí)例,A.class_foo(x).注意這里的self和cls可以替換別的參數(shù),但是python的約定是這倆,還是不要改的好.

對(duì)于靜態(tài)方法其實(shí)和普通的方法一樣,不需要對(duì)誰進(jìn)行綁定,唯一的區(qū)別是調(diào)用的時(shí)候需要使用a.static_foo(x)或者A.static_foo(x)來調(diào)用.

\ 實(shí)例方法 類方法 靜態(tài)方法
a = A() a.foo(x) a.class_foo(x) a.static_foo(x)
A 不可用 A.class_foo(x) A.static_foo(x)

更多關(guān)于這個(gè)問題:

  1. http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python
  2. https://realpython.com/blog/python/instance-class-and-static-methods-demystified/

13 使用property創(chuàng)建可管理的對(duì)象屬性

property可以讓實(shí)例在形式上是屬性訪問,但實(shí)際上調(diào)用方法

class Circle2(object):
    def __init__(self, radius):
        self.radius = radius

    def getRadius(self):
        # return self.radius
        return round(self.radius, 2)  # 表示四舍五入后保留小數(shù)點(diǎn)后兩位

    def setRadius(self, value):
        if not isinstance(value, (int, long, float)):
            raise valueError('wrong type .')
        self.radius = float(value)

    def getArea(self):
        return self.radius * 2 * pi

    R = property(getRadius, setRadius)

r = Circle2(3.2)
print(r.R)  # 自動(dòng)調(diào)用getRadius
r.R = 5.4  # 自動(dòng)調(diào)用setRadius
print(r.R)  # 自動(dòng)調(diào)用getRadius

14 類屬性和實(shí)例屬性

? 是可在類的所有實(shí)例之間共享的值(也就是說汇在,它們不是單獨(dú)分配給每個(gè)實(shí)例的)翰萨。例如下例中,num_of_instance 就是類屬性糕殉,用于跟蹤存在著多少個(gè)Test 的實(shí)例亩鬼。

實(shí)例屬性:

實(shí)例化之后,每個(gè)實(shí)例單獨(dú)擁有的變量阿蝶。

class Test(object):  
    num_of_instance = 0  
    def __init__(self, name):  
        self.name = name  
        Test.num_of_instance += 1  

if __name__ == '__main__':  
    print Test.num_of_instance   # 0
    t1 = Test('jack')  
    print Test.num_of_instance   # 1
    t2 = Test('lucy')  
    print t1.name , t1.num_of_instance  # jack 2
    print t2.name , t2.num_of_instance  # lucy 2

補(bǔ)充的例子

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"是實(shí)例調(diào)用了類屬性,這其實(shí)和上面第一個(gè)問題一樣,就是函數(shù)傳參的問題,p1.name一開始是指向的類屬性name="aaa",但是在實(shí)例的作用域里把類屬性的引用改變了,就變成了一個(gè)實(shí)例屬性,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

15 Python自省

這個(gè)也是python彪悍的特性.

自省就是面向?qū)ο蟮恼Z言所寫的程序在運(yùn)行時(shí),所能知道對(duì)象的類型.簡(jiǎn)單一句就是運(yùn)行時(shí)能夠獲得對(duì)象的類型.比如type(),dir(),getattr(),hasattr(),isinstance().

a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print type(a),type(b),type(c) # <type 'list'> <type 'dict'> <type 'bool'>
print isinstance(a,list)  # True

16 字典解析雳锋、列表解析、集合解析

代碼示例如下:

list1=[x for x in range(100) if x%2==0] #或 [x for x in range(0,100,2)]
L = list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
L2 = list(filter(lambda x: x > 0, [1. - 1, -3, -4, 3, 3, 45, 34]))
#集合的列表生成式
s={1,34,5,-7,6,87,-8,-9,11}
print({x for x in s if x%3==0})
#補(bǔ)充:集合的交集并集等操作
A=set([randint(1,20) for _ in range(10)])
B=set([randint(1,20) for _ in range(10)])
print(A&B,A|B,A-B,A^B) #交羡洁,并玷过,差,補(bǔ)

d = {key: value for (key, value) in iterable if key**}
#補(bǔ)充 如何根據(jù)字典中值的大小,對(duì)字典中的項(xiàng)排序
#方案1 使用zip將字典數(shù)據(jù)轉(zhuǎn)化為元組
score = {
    'LiLei': 79,
    'Jim': 88,
    'Lucy': 92
}
score4 = tuple(zip(score.values(),score.keys()))
score5 = sorted(score4)
##直接用sorted,
print(sorted(score.items(),key=lambda x:x[1])) #表示對(duì)生成的列表的元組索引第二位進(jìn)行排序
#補(bǔ)充 k,v交換
score2={v:k for k,v in score.items()}
score3=dict(zip(score2.values(),score2.keys()))

補(bǔ)充1 如何為元組的每個(gè)元素命名,提高程序可讀性

from collections import namedtuple
Student = namedtuple('Student', ['name', 'age', 'sex', 'email'])
Jim = Student('Jim', 16, 'male', 'jim8721@gamil.com')
print(Jim.name)
print(Jim.age)
print(Jim.sex)
print(Jim.email)

補(bǔ)充2 如何統(tǒng)計(jì)序列中元素的出現(xiàn)頻度

from collections import Counter, OrderedDict
from random import randint
import re

data = [randint(0, 20) for _ in range(30)] #產(chǎn)生30個(gè)0到20的隨機(jī)整數(shù)
print(Counter(data))
print(Counter(data).most_common(3))

補(bǔ)充3 如何快速找到多個(gè)字典中的公共鍵(key)

from functools import reduce

N1 = {
    '蘇亞雷斯': 1,
    '梅西': 2,
    '本澤馬': 1,
    'C羅': 3
}

N2 = {
    '蘇亞雷斯': 2,
    'C羅': 1,
    '格里子曼': 2,
    '貝爾': 1
}

N3 = {
    '蘇亞雷斯': 1,
    '托雷斯': 2,
    '內(nèi)馬爾': 1,
    '貝爾': 1
}

# 統(tǒng)計(jì)出每輪比賽都有進(jìn)球的球員
res = []
for k in N1:
    if k in N2 and k in N3:
        res.append(k)

print(res)
#解決方案:
'''
利用set集合的交集操作
1.使用dict的viewkeys()方法,返回一個(gè)dict.keys()的集合
2.使用map函數(shù),得到所有字典的keys的集合
3.使用reduce函數(shù),取所有字典的keys的集合的交集
'''
print(reduce(lambda x,y:x &y,list(map(dict.keys,[N1,N2,N3]))))

補(bǔ)充4 創(chuàng)建有序的字典

from functools import OrderedDict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 字典輸出可以按插入的順序排序并輸出

補(bǔ)充5 元組和列表的同異

同:列表與元組都是容器筑煮,是一系列的對(duì)象辛蚊。二者都可以包含任意類型的元素甚至可以是一個(gè)序列,還可以包含元素的順序(不像集合和字典)咆瘟。
元組屬于不可變對(duì)象嚼隘,列表屬于可變對(duì)象,列表的很多方法不適用于元組袒餐;元組可哈希而列表不可哈希飞蛹;元組占用空間更小,代碼的語義更好理解再函數(shù)式編程較常用灸眼。

17 Python中單下劃線和雙下劃線

>>> 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內(nèi)部的名字,用來區(qū)別其他用戶自定義的命名,以防沖突卧檐,就是例如__init__(),__del__(),__call__()這些特殊方法

_foo:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.不能用from module import * 導(dǎo)入,其他方面和公有一樣訪問焰宣;

__foo:這個(gè)有真正的意義:解析器用_classname__foo來代替這個(gè)名字,以區(qū)別和其他類相同的命名,它無法直接像公有成員一樣隨便訪問,通過對(duì)象名._類名__xxx這樣的方式可以訪問.

詳情見:http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python

或者: http://www.zhihu.com/question/19754941

18 字符串格式化:%和.format

.format在許多方面看起來更便利.對(duì)于%最煩人的是它無法同時(shí)傳遞一個(gè)變量和元組.你可能會(huì)想下面的代碼不會(huì)有什么問題:

"hi there %s" % name

但是,如果name恰好是(1,2,3),它將會(huì)拋出一個(gè)TypeError異常.為了保證它總是正確的,你必須這樣做:

"hi there %s" % (name,)   # 提供一個(gè)單元素的數(shù)組而不是一個(gè)參數(shù)

但是有點(diǎn)丑..format就沒有這些問題.你給的第二個(gè)問題也是這樣,.format好看多了.

你為什么不用它?

  • 不知道它(在讀這個(gè)之前)
  • 為了和Python2.5兼容(譬如logging庫建議使用%(issue #4))

http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format

19 正則表達(dá)式相關(guān)知識(shí)及字符串操作

參考廖雪峰

  • 字符串拼接join方法
    str.join(iterable)
L = ["<0112>", "<32>", "<1024x768>", 60, "<1>", "<100.0>", "<500.0>"]
print(''.join(str(x) for x in L))
  • 如何判斷字符串a(chǎn)是否以字符串b開頭或結(jié)尾,str.startswith(),str.endswith()
a="abcdefg||fadfa.py"
a.endswith(('.py','.sh'))
  • 如何用Python來進(jìn)行查詢和替換一個(gè)文本字符串霉囚?
s = '\tabd\t124\txyz\r\n'
print(re.sub('\t|\r|\n','',s))
  • 一次性拆分字符串 re.split(),str.split()
"""
解決方案:
方法一:連續(xù)使用是str.split()方法,每次處理一種分隔符號(hào)
方法二:使用正則表達(dá)式的re.split()方法,一次性拆分字符串
"""
s = 'ab;cd|efg|hi,jklmn|topq;rst,uvw|txyz'
t = s.split(';')
t1 = re.split(r'[,;|\t]+',s)
  • Python里面match()和search()的區(qū)別?
re模塊中match(pattern,string[,flags]),檢查string的開頭是否與pattern匹配匕积。
re模塊中re.search(pattern,string[,flags]),在string搜索pattern的第一個(gè)匹配值盈罐。
  • Python re.findall()方法
#尋找一段字符串中的11位數(shù)字(手機(jī)號(hào))榜跌,返回列表
import re
str1="13832244324gdsjsfhauer13632996133"
re.findall(r'\d{11}',str1)
  • 用Python匹配HTML tag的時(shí)候,<.>和<.?>有什么區(qū)別盅粪?
    答:術(shù)語叫貪婪匹配( <.> )和非貪婪匹配(<.?> )
    前者是貪婪匹配钓葫,會(huì)從頭到尾匹配 <a>xyz</a>,而后者是非貪婪匹配票顾,只匹配到第一個(gè) >础浮。
  • 如何去掉字符串中不需要的字符
"""
解決方案:
方法1:字符串strip(),lstrip(),rstrip()方法去掉字符串兩段字符
方法2:刪除單個(gè)固定位置的字符,可以使用切片+拼接的方式
方法3:字符串的replace()方法或正則表達(dá)式re.sub()刪除任意位置字符
方法4:字符串translate()方法,可以同時(shí)刪除多種不同字符
"""

s='  nick2008@gmail.com  '
print(s.strip(' '))
print('----------------')
s = '====+-----'
print(s.strip('-='))
print('----------------')
s='  nick2008  @gmail.com  '
print(s[2:11]+s[12:23])
print('----------------')

s = '\tabd\t124\txyz\r\n'
print(s.replace('\t',''))
print('----------------')
s = '\tabd\t124\txyz\r\n'
print(re.sub('\t|\r|\n','',s))
print('----------------')
s = '\tabd\t124\txyz\r\n'
print(s.translate(None,'\t\r\n'))

s = '\tabd\t124\txyz\r\n'
print(s.replace('\t',''))
u = u'uulàlà,là,māmá'
print u.translate(dict.fromkeys([0x0,0x0101,0x1]))
  • 補(bǔ)充 單引號(hào),雙引號(hào)奠骄,三引號(hào)的區(qū)別

答:?jiǎn)我?hào)和雙引號(hào)是等效的豆同,如果要換行,需要符號(hào)(),三引號(hào)則可以直接換行含鳞,并且可以包含注釋

如果要表示Let’s go 這個(gè)字符串

單引號(hào):s4 = ‘Let\’s go’

雙引號(hào):s5 = “Let’s go”

s6 = ‘I realy like“python”!’

這就是單引號(hào)和雙引號(hào)都可以表示字符串的原因了

20 迭代器和生成器

這個(gè)是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

這里有個(gè)關(guān)于生成器的創(chuàng)建問題面試官有考:
問: 將列表生成式中[]改成() 之后數(shù)據(jù)結(jié)構(gòu)是否改變珍策?
答案:是姑隅,從列表變?yōu)樯善?/p>

>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000028F8B774200>

通過列表生成式圆裕,可以直接創(chuàng)建一個(gè)列表胳蛮。但是烫堤,受到內(nèi)存限制躯砰,列表容量肯定是有限的活箕。而且魂仍,創(chuàng)建一個(gè)包含百萬元素的列表沃但,不僅是占用很大的內(nèi)存空間磁滚,如:我們只需要訪問前面的幾個(gè)元素,后面大部分元素所占的空間都是浪費(fèi)的宵晚。因此垂攘,沒有必要?jiǎng)?chuàng)建完整的列表(節(jié)省大量?jī)?nèi)存空間)。在Python中淤刃,我們可以采用生成器:邊循環(huán)晒他,邊計(jì)算的機(jī)制—>generator

大數(shù)據(jù)的文件讀取

with open(path,'rb') as file:
    for line in file:
        print(file)

yield語句的用法

相當(dāng)于給函數(shù)運(yùn)行打斷點(diǎn),下次循環(huán)或者調(diào)用時(shí)在這里終止程序
yield簡(jiǎn)單說來就是一個(gè)生成器逸贾,這樣函數(shù)它記住上次返 回時(shí)在函數(shù)體中的位置陨仅。對(duì)生成器第 二次(或n 次)調(diào)用跳轉(zhuǎn)至該函樹)調(diào)用跳轉(zhuǎn)至該函數(shù)。

21 *args and **kwargs

*args**kwargs只是為了方便并沒有強(qiáng)制使用它們.

當(dāng)你不確定你的函數(shù)里將要傳遞多少參數(shù)時(shí)你可以用*args.例如,它可以傳遞任意數(shù)量的參數(shù):

>>> 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允許你使用沒有事先定義的參數(shù)名:

>>> 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

你也可以混著用.命名參數(shù)首先獲得參數(shù)值然后所有的其他參數(shù)都傳遞給*args**kwargs.命名參數(shù)在列表的最前端.例如:

def table_things(titlestring, **kwargs)

*args**kwargs可以同時(shí)在函數(shù)的定義中,但是*args必須在**kwargs前面.

當(dāng)調(diào)用函數(shù)時(shí)你也可以用***語法.例如:

>>> 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

就像你看到的一樣,它可以傳遞列表(或者元組)的每一項(xiàng)并把它們解包.注意必須與它們?cè)诤瘮?shù)里的參數(shù)相吻合.當(dāng)然,你也可以在函數(shù)定義或者函數(shù)調(diào)用時(shí)用*.

http://stackoverflow.com/questions/3394835/args-and-kwargs

22 裝飾器

裝飾器是一個(gè)很著名的設(shè)計(jì)模式铝侵,經(jīng)常被用于有切面需求的場(chǎng)景灼伤,較為經(jīng)典的有計(jì)時(shí)統(tǒng)計(jì)、插入日志咪鲜、緩存計(jì)算結(jié)果狐赡、性能測(cè)試、事務(wù)處理等疟丙。裝飾器是解決這類問題的絕佳設(shè)計(jì)颖侄,有了裝飾器鸟雏,我們就可以抽離出大量函數(shù)中與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。概括的講览祖,裝飾器的作用就是為已經(jīng)存在的對(duì)象添加額外的功能孝鹊。
裝飾器的作用和功能:

  • 引入日志
  • 函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)
  • 執(zhí)行函數(shù)前預(yù)備處理
  • 執(zhí)行函數(shù)后的清理功能
  • 權(quán)限校驗(yàn)等場(chǎng)景
  • 緩存

下面舉例說明

裝飾器用做日志記錄

from functools import wrapper
def log(func):
    @functools.wraps(func) # 將func的屬性傳遞給wrapper
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        f=func(*args, **kw)
        print('end call %s():' % func.__name__)
        return f    
    return wrapper

如何定義帶參數(shù)的裝飾器

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
# 同時(shí)支持@log和@log('execute')
def log2(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            if isinstance(text,str):
                print('%s %s():' % (text, func.__name__))
            else:
                print('%s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    if callable(text):
        return decorator(text)
    else:
        return decorator

裝飾器用做執(zhí)行時(shí)間統(tǒng)計(jì)


from functools import wrapper
from time import time
def metric(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        t0 = time()
        func(*args, **kw)
        print('%s executed in %s ms' % (func.__name__, (time() - t0) * 1000))
        return func
    return wrapper

裝飾器用做緩存


def meomo(func):
    cache = {}
    def wrap(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrap
@meomo
def fibonacci(n):
    if n<=1:
        return 1
    cache = fibonacci(n-1)+fibonacci(n-2)
    return cache
"""一個(gè)共有十個(gè)10個(gè)臺(tái)階的樓梯,從下面走到上面,一次只能邁1-3個(gè)臺(tái)階,
并且不能后退,走完這個(gè)樓梯共有多少種方法"""
'''
@meomo
def climb(n,steps):
    count = 0
    if n == 0:
        count +=1
    elif n>0:
        for step in steps:
            count += climb(n-step,steps)
    return count

這個(gè)問題比較大,推薦: 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

23 Python中重載

引自知乎:http://www.zhihu.com/question/20053359

函數(shù)重載主要是為了解決兩個(gè)問題。

  1. 可變參數(shù)類型穴墅。
  2. 可變參數(shù)個(gè)數(shù)惶室。

另外,一個(gè)基本的設(shè)計(jì)原則是玄货,僅僅當(dāng)兩個(gè)函數(shù)除了參數(shù)類型和參數(shù)個(gè)數(shù)不同以外皇钞,其功能是完全相同的,此時(shí)才使用函數(shù)重載松捉,如果兩個(gè)函數(shù)的功能其實(shí)不同夹界,那么不應(yīng)當(dāng)使用重載,而應(yīng)當(dāng)使用一個(gè)名字不同的函數(shù)隘世。

好吧可柿,那么對(duì)于情況 1 ,函數(shù)功能相同丙者,但是參數(shù)類型不同复斥,python 如何處理?答案是根本不需要處理械媒,因?yàn)?python 可以接受任何類型的參數(shù)目锭,如果函數(shù)的功能相同,那么不同的參數(shù)類型在 python 中很可能是相同的代碼纷捞,沒有必要做成兩個(gè)不同函數(shù)痢虹。

那么對(duì)于情況 2 ,函數(shù)功能相同主儡,但參數(shù)個(gè)數(shù)不同奖唯,python 如何處理?大家知道糜值,答案就是缺省參數(shù)丰捷。對(duì)那些缺少的參數(shù)設(shè)定為缺省參數(shù)即可解決問題。因?yàn)槟慵僭O(shè)函數(shù)功能相同臀玄,那么那些缺少的參數(shù)終歸是需要用的瓢阴。

好了,鑒于情況 1 跟 情況 2 都有了解決方案健无,python 自然就不需要函數(shù)重載了荣恐。

24 __new____init__的區(qū)別

這個(gè)__new__確實(shí)很少見到,先做了解吧.

  1. __new__是一個(gè)靜態(tài)方法,而__init__是一個(gè)實(shí)例方法.
  2. __new__方法會(huì)返回一個(gè)創(chuàng)建的實(shí)例,而__init__什么都不返回.
  3. 只有在__new__返回一個(gè)cls的實(shí)例時(shí)后面的__init__才能被調(diào)用.
  4. 當(dāng)創(chuàng)建一個(gè)新實(shí)例時(shí)調(diào)用__new__,初始化一個(gè)實(shí)例時(shí)用__init__.

stackoverflow

ps: __metaclass__是創(chuàng)建類時(shí)起作用.所以我們可以分別使用__metaclass__,__new____init__來分別在類創(chuàng)建,實(shí)例創(chuàng)建和實(shí)例初始化的時(shí)候做一些小手腳.

25 單例模式

? 單例模式是一種常用的軟件設(shè)計(jì)模式。在它的核心結(jié)構(gòu)中只包含一個(gè)被稱為單例類的特殊類。通過單例模式可以保證系統(tǒng)中一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問叠穆,從而方便對(duì)實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源少漆。如果希望在系統(tǒng)中某個(gè)類的對(duì)象只能存在一個(gè),單例模式是最好的解決方案硼被。

__new__()__init__()之前被調(diào)用示损,用于生成實(shí)例對(duì)象。利用這個(gè)方法和類的屬性的特點(diǎn)可以實(shí)現(xiàn)設(shè)計(jì)模式的單例模式嚷硫。單例模式是指創(chuàng)建唯一對(duì)象检访,單例模式設(shè)計(jì)的類只能實(shí)例
這個(gè)絕對(duì)常考啊.絕對(duì)要記住1~2個(gè)方法,當(dāng)時(shí)面試官是讓手寫的.

1 使用__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

2 共享屬性

創(chuàng)建實(shí)例時(shí)把所有實(shí)例的__dict__指向同一個(gè)字典,這樣它們具有相同的屬性和方法.


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

3 裝飾器版本

def singleton(cls):
    instances = {}
    def getinstance(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

4 import方法

作為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()

單例模式伯樂在線詳細(xì)解釋

26 Python中的作用域

Python 中仔掸,一個(gè)變量的作用域總是由在代碼中被賦值的地方所決定的脆贵。

當(dāng) Python 遇到一個(gè)變量的話他會(huì)按照這樣的順序進(jìn)行搜索:

本地作用域(Local)→當(dāng)前作用域被嵌入的本地作用域(Enclosing locals)→全局/模塊作用域(Global)→內(nèi)置作用域(Built-in)

27 GIL線程全局鎖

Python代碼的執(zhí)行由Python 虛擬機(jī)(也叫解釋器主循環(huán),CPython版本)來控制起暮,Python 在設(shè)計(jì)之初就考慮到要在解釋器的主循環(huán)中卖氨,同時(shí)只有一個(gè)線程在執(zhí)行,即在任意時(shí)刻负懦,只有一個(gè)線程在解釋器中運(yùn)行筒捺。對(duì)Python 虛擬機(jī)的訪問由全局解釋器鎖(GIL)來控制,正是這個(gè)鎖能保證同一時(shí)刻只有一個(gè)線程在運(yùn)行纸厉。線程的執(zhí)行速度非常之快系吭,會(huì)讓你誤以為線程是并行執(zhí)行的(并行),但是實(shí)際上都是輪流執(zhí)行(并發(fā)或者串行)颗品。對(duì)于io密集型任務(wù)村斟,python的多線程起到作用,但對(duì)于cpu密集型任務(wù)抛猫,python的多線程幾乎占不到任何優(yōu)勢(shì),還有可能因?yàn)闋?zhēng)奪資源而變慢孩灯。
在多線程環(huán)境中闺金,Python 虛擬機(jī)按以下方式執(zhí)行:

  1. 設(shè)置GIL
  2. 切換到一個(gè)線程去運(yùn)行
  3. 運(yùn)行:
    a. 指定數(shù)量的字節(jié)碼指令,或者
    b. 線程主動(dòng)讓出控制(可以調(diào)用time.sleep(0))
  4. 把線程設(shè)置為睡眠狀態(tài)
  5. 解鎖GIL
  6. 再次重復(fù)以上所有步驟
    在調(diào)用外部代碼(如C/C++擴(kuò)展函數(shù))的時(shí)候峰档,GIL 將會(huì)被鎖定败匹,直到這個(gè)函數(shù)結(jié)束為止(由于在這期間沒有Python 的字節(jié)碼被運(yùn)行,所以不會(huì)做線程切換)讥巡。
    join方法 子進(jìn)程結(jié)束切換到父進(jìn)程
    多進(jìn)程應(yīng)該避免共享資源掀亩。在多線程中,我們可以比較容易地共享資源欢顷,比如使用全局變量或者傳遞參數(shù)槽棍。在多進(jìn)程情況下,由于每個(gè)進(jìn)程有自己獨(dú)立的內(nèi)存空間,以上方法并不合適炼七。此時(shí)我們可以通過共享內(nèi)存和Manager的方法來共享資源缆巧。但這樣做提高了程序的復(fù)雜度,并因?yàn)橥降男枰档土顺绦虻男省?/li>

Python 最難的問題

解決辦法就是多進(jìn)程和下面的協(xié)程(協(xié)程也只是單CPU,但是能減小切換代價(jià)提升性能).

28 協(xié)程

參考廖雪峰

簡(jiǎn)單點(diǎn)說協(xié)程是進(jìn)程和線程的升級(jí)版,進(jìn)程和線程都面臨著內(nèi)核態(tài)和用戶態(tài)的切換問題而耗費(fèi)許多切換時(shí)間,而協(xié)程就是用戶自己控制切換的時(shí)機(jī),不再需要陷入系統(tǒng)的內(nèi)核態(tài).

Python對(duì)協(xié)程的支持是通過generator實(shí)現(xiàn)的豌拙。

29 閉包

閉包(closure)是函數(shù)式編程的重要的語法結(jié)構(gòu)陕悬。閉包也是一種組織代碼的結(jié)構(gòu),它同樣提高了代碼的可重復(fù)使用性按傅。

當(dāng)一個(gè)內(nèi)嵌函數(shù)引用其外部作作用域的變量,我們就會(huì)得到一個(gè)閉包. 總結(jié)一下,創(chuàng)建一個(gè)閉包必須滿足以下幾點(diǎn):

  1. 必須有一個(gè)內(nèi)嵌函數(shù)
  2. 內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量
  3. 外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)

感覺閉包還是有難度的,幾句話是說不明白的,還是查查相關(guān)資料.

重點(diǎn)是函數(shù)運(yùn)行后并不會(huì)被撤銷,就像16題的instance字典一樣,當(dāng)函數(shù)運(yùn)行完后,instance并不被銷毀,而是繼續(xù)留在內(nèi)存空間里.這個(gè)功能類似類里的類屬性,只不過遷移到了函數(shù)上.

閉包就像個(gè)空心球一樣,你知道外面和里面,但你不知道中間是什么樣.

30 lambda函數(shù)

其實(shí)就是一個(gè)匿名函數(shù),為什么叫l(wèi)ambda?因?yàn)楹秃竺娴暮瘮?shù)式編程有關(guān).

推薦: 知乎

31 Python函數(shù)式編程

這個(gè)需要適當(dāng)?shù)牧私庖幌掳?畢竟函數(shù)式編程在Python中也做了引用.

推薦: 酷殼

python中函數(shù)式編程支持:

filter 函數(shù)的功能相當(dāng)于過濾器捉超。調(diào)用一個(gè)布爾函數(shù)bool_func來迭代遍歷每個(gè)seq中的元素;返回一個(gè)使bool_seq返回值為true的元素的序列唯绍。

>>>a = [1,2,3,4,5,6,7]
>>>b = filter(lambda x: x > 5, a)
>>>print b
>>>[6,7]

map函數(shù)是對(duì)一個(gè)序列的每個(gè)項(xiàng)依次執(zhí)行函數(shù)拼岳,下面是對(duì)一個(gè)序列每個(gè)項(xiàng)都乘以2:

>>> a = map(lambda x:x*2,[1,2,3])
>>> list(a)
[2, 4, 6]

reduce函數(shù)是對(duì)一個(gè)序列的每個(gè)項(xiàng)迭代調(diào)用函數(shù),下面是求3的階乘:

>>> reduce(lambda x,y:x*y,range(1,4))
6

filter函數(shù)用于對(duì)序列的每個(gè)項(xiàng)進(jìn)行迭代推捐,不滿足條件的就會(huì)被踢出序列

>>> filter(lambda x>0:x,range(-10,4))
[1,2,3]

補(bǔ)充:用filter求素?cái)?shù)

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n
def _not_divisible(n):
    return lambda x: x % n > 0
def primes():
    yield 2
    it = _odd_iter() # 初始序列
    while True:
        n = next(it) # 返回序列的第一個(gè)數(shù)
        yield n
        it = filter(_not_divisible(n), it) # 構(gòu)造新序列
# 打印1000以內(nèi)的素?cái)?shù):
for n in primes():
    if n < 1000:
        print(n)
    else:
        break

32 Python里的拷貝

引用和copy(),deepcopy()的區(qū)別

import copy
a = [1, 2, 3, 4, ['a', 'b']]  #原始對(duì)象

b = a  #賦值裂问,傳對(duì)象的引用
c = copy.copy(a)  #對(duì)象拷貝,淺拷貝
d = copy.deepcopy(a)  #對(duì)象拷貝牛柒,深拷貝

a.append(5)  #修改對(duì)象a
a[4].append('c')  #修改對(duì)象a中的['a', 'b']數(shù)組對(duì)象

print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d

輸出結(jié)果:
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']]

切片的對(duì)象堪簿,切片是淺拷貝還是深拷貝
切片的對(duì)象有l(wèi)ist,tuple,str
“=”,copy,slice屬于淺拷貝
deepcopy就屬于深拷貝
淺拷貝和深拷貝的區(qū)別在于深拷貝是被復(fù)制的對(duì)象作為一個(gè)新的個(gè)體獨(dú)立存在,
任意改變其一不會(huì)對(duì)另一個(gè)對(duì)象造成影響,而淺拷貝不會(huì)產(chǎn)生新的獨(dú)立對(duì)象

33 Python是如何進(jìn)行內(nèi)存管理的

(http://developer.51cto.com/art/201007/213585.html)

答:從三個(gè)方面來說,一對(duì)象的引用計(jì)數(shù)機(jī)制,二垃圾回收機(jī)制,三內(nèi)存池機(jī)制

  • 1、對(duì)象的引用計(jì)數(shù)機(jī)制

Python內(nèi)部使用引用計(jì)數(shù)皮壁,來保持追蹤內(nèi)存中的對(duì)象椭更,所有對(duì)象都有引用計(jì)數(shù)。

引用計(jì)數(shù)增加的情況:

1蛾魄,一個(gè)對(duì)象分配一個(gè)新名稱

2虑瀑,將其放入一個(gè)容器中(如列表、元組或字典)

引用計(jì)數(shù)減少的情況:

1滴须,使用del語句對(duì)對(duì)象別名顯示的銷毀

2舌狗,引用超出作用域或被重新賦值

sys.getrefcount( )函數(shù)可以獲得對(duì)象的當(dāng)前引用計(jì)數(shù)

多數(shù)情況下,引用計(jì)數(shù)比你猜測(cè)得要大得多扔水。對(duì)于不可變數(shù)據(jù)(如數(shù)字和字符串)痛侍,解釋器會(huì)在程序的不同部分共享內(nèi)存,以便節(jié)約內(nèi)存魔市。

  • 2主届、垃圾回收

1,當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)歸零時(shí)待德,它將被垃圾收集機(jī)制處理掉君丁。

2,當(dāng)兩個(gè)對(duì)象a和b相互引用時(shí)将宪,del語句可以減少a和b的引用計(jì)數(shù)绘闷,并銷毀用于引用底層對(duì)象的名稱橡庞。然而由于每個(gè)對(duì)象都包含一個(gè)對(duì)其他對(duì)象的應(yīng)用,

因此引用計(jì)數(shù)不會(huì)歸零簸喂,對(duì)象也不會(huì)銷毀毙死。(從而導(dǎo)致內(nèi)存泄露)。為解決這一問題喻鳄,解釋器會(huì)定期執(zhí)行一個(gè)循環(huán)檢測(cè)器扼倘,搜索不可訪問對(duì)象的循環(huán)并刪除它們。

  • 3除呵、內(nèi)存池機(jī)制

Python提供了對(duì)內(nèi)存的垃圾收集機(jī)制再菊,但是它將不用的內(nèi)存放到內(nèi)存池而不是返回給操作系統(tǒng)。

1颜曾,Pymalloc機(jī)制纠拔。為了加速Python的執(zhí)行效率,Python引入了一個(gè)內(nèi)存池機(jī)制泛豪,用于管理對(duì)小塊內(nèi)存的申請(qǐng)和釋放稠诲。

2,Python中所有小于256個(gè)字節(jié)的對(duì)象都使用pymalloc實(shí)現(xiàn)的分配器诡曙,而大的對(duì)象則使用系統(tǒng)的malloc臀叙。

3,對(duì)于Python對(duì)象价卤,如整數(shù)劝萤,浮點(diǎn)數(shù)和List,都有其獨(dú)立的私有內(nèi)存池慎璧,對(duì)象間不共享他們的內(nèi)存池床嫌。也就是說如果你分配又釋放了大量的整數(shù),用于緩存這些整數(shù)的內(nèi)存就不能再分配給浮點(diǎn)數(shù)胸私。

34 Python的List和Dict的實(shí)現(xiàn)原理

推薦:
列表
字典

  • 字典按照鍵值對(duì)的形式進(jìn)行存儲(chǔ)厌处,時(shí)間復(fù)雜度為O(1)
  • 字典的底層是通過哈希表實(shí)現(xiàn)的,使用開放地址法解決沖突岁疼。所以其查找的時(shí)間復(fù)雜度會(huì)是O(1)嘱蛋,哈希函數(shù)求哈希值

35 Python的is和==

is是對(duì)比地址,==是對(duì)比值
is 比較的是兩個(gè)實(shí)例對(duì)象是不是完全相同,is關(guān)鍵字是查看兩個(gè)對(duì)象是否相同的唯一標(biāo)準(zhǔn),他們是不是同一個(gè)對(duì)象,
占用的內(nèi)存地址是否相同,即比較他們的id
== 比較的是兩個(gè)實(shí)例對(duì)象的內(nèi)容是否相同,即他們的內(nèi)存地址可以不同,默認(rèn)調(diào)用eq方法
切片slice is->False ==->True
序列直接復(fù)制= is->True
大量創(chuàng)建相同內(nèi)容的字符串五续,is->True
小整數(shù)對(duì)象[-5,256]在全局解釋器范圍內(nèi)被放入緩存共重復(fù)使用
a=1 b=1 a is b ->True ==->True
a=257 b=257 a is b ->True ==->True

is運(yùn)算符比==效率高,在變量和None進(jìn)行比較時(shí),應(yīng)該使用is

36 read,readline和readlines

  • read 讀取整個(gè)文件
  • readline 讀取下一行,使用生成器方法
  • readlines 讀取整個(gè)文件到一個(gè)迭代器以供我們遍歷

37 Python2和3的區(qū)別

推薦:Python 2.7.x 與 Python 3.x 的主要差異

補(bǔ)充:Python的編碼問題

python3 bytes和str都可以代表字符序列,前者的實(shí)例包含原始的8位值;bytes.decode('utf-8')
后者的實(shí)例包含unicode字符 str.encode('utf-8')

python2 str和Unicode都可以代表字符序列,與python3不同的是,str的實(shí)例包含原始的8位值,str.decode('utf-8')
而Unicode的實(shí)例則包含unicode字符,unicode.encode(‘utf-8’)

python2 str <--> python3 bytes
python2 unicode <--> python3 str

python2 str.decode(‘utf-8’)–>unicode
unicode.encode(‘utf-8’)–>str
python3 bytes.decode(‘utf-8’)–>str
str.encode(‘utf-8’) –>bytes

數(shù)據(jù)庫

1 事務(wù)

數(shù)據(jù)庫事務(wù)(Database Transaction) ,是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作龄恋,要么完全地執(zhí)行疙驾,要么完全地不執(zhí)行。
徹底理解數(shù)據(jù)庫事務(wù): http://www.hollischuang.com/archives/898

2 數(shù)據(jù)庫索引

推薦: http://tech.meituan.com/mysql-index.html

MySQL索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理

聚集索引,非聚集索引,B-Tree,B+Tree,最左前綴原理

3 Redis原理

Redis是什么郭毕?

  1. 是一個(gè)完全開源免費(fèi)的key-value內(nèi)存數(shù)據(jù)庫
  2. 通常被認(rèn)為是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù)器它碎,主要是因?yàn)槠溆兄S富的數(shù)據(jù)結(jié)構(gòu) strings、map、 list扳肛、sets傻挂、 sorted sets

Redis數(shù)據(jù)庫

? 通常局限點(diǎn)來說,Redis也以消息隊(duì)列的形式存在挖息,作為內(nèi)嵌的List存在金拒,滿足實(shí)時(shí)的高并發(fā)需求。在使用緩存的時(shí)候套腹,redis比memcached具有更多的優(yōu)勢(shì)绪抛,并且支持更多的數(shù)據(jù)類型,把redis當(dāng)作一個(gè)中間存儲(chǔ)系統(tǒng)电禀,用來處理高并發(fā)的數(shù)據(jù)庫操作

  • 速度快:使用標(biāo)準(zhǔn)C寫幢码,所有數(shù)據(jù)都在內(nèi)存中完成,讀寫速度分別達(dá)到10萬/20萬
  • 持久化:對(duì)數(shù)據(jù)的更新采用Copy-on-write技術(shù)尖飞,可以異步地保存到磁盤上症副,主要有兩種策略,一是根據(jù)時(shí)間政基,更新次數(shù)的快照(save 300 10 )二是基于語句追加方式(Append-only file贞铣,aof)
  • 自動(dòng)操作:對(duì)不同數(shù)據(jù)類型的操作都是自動(dòng)的,很安全
  • 快速的主--從復(fù)制腋么,官方提供了一個(gè)數(shù)據(jù)咕娄,Slave在21秒即完成了對(duì)Amazon網(wǎng)站10G key set的復(fù)制。
  • Sharding技術(shù): 很容易將數(shù)據(jù)分布到多個(gè)Redis實(shí)例中珊擂,數(shù)據(jù)庫的擴(kuò)展是個(gè)永恒的話題圣勒,在關(guān)系型數(shù)據(jù)庫中,主要是以添加硬件摧扇、以分區(qū)為主要技術(shù)形式的縱向擴(kuò)展解決了很多的應(yīng)用場(chǎng)景圣贸,但隨著web2.0、移動(dòng)互聯(lián)網(wǎng)扛稽、云計(jì)算等應(yīng)用的興起吁峻,這種擴(kuò)展模式已經(jīng)不太適合了,所以近年來在张,像采用主從配置用含、數(shù)據(jù)庫復(fù)制形式的,Sharding這種技術(shù)把負(fù)載分布到多個(gè)特理節(jié)點(diǎn)上去的橫向擴(kuò)展方式用處越來越多帮匾。

Redis缺點(diǎn)

  • 是數(shù)據(jù)庫容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場(chǎng)景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上啄骇。
  • Redis較難支持在線擴(kuò)容,在集群容量達(dá)到上限時(shí)在線擴(kuò)容會(huì)變得很復(fù)雜瘟斜。為避免這一問題缸夹,運(yùn)維人員在系統(tǒng)上線時(shí)必須確保有足夠的空間痪寻,這對(duì)資源造成了很大的浪費(fèi)。

4 MyISAM和InnoDB

MyISAM 適合于一些需要大量查詢的應(yīng)用虽惭,但其對(duì)于有大量寫操作并不是很好橡类。甚至你只是需要update一個(gè)字段,整個(gè)表都會(huì)被鎖起來芽唇,而別的進(jìn)程顾画,就算是讀進(jìn)程都無法操作直到讀操作完成。另外披摄,MyISAM 對(duì)于 SELECT COUNT(*) 這類的計(jì)算是超快無比的亲雪。

InnoDB 的趨勢(shì)會(huì)是一個(gè)非常復(fù)雜的存儲(chǔ)引擎,對(duì)于一些小的應(yīng)用疚膊,它會(huì)比 MyISAM 還慢义辕。他是它支持“行鎖” ,于是在寫操作比較多的時(shí)候寓盗,會(huì)更優(yōu)秀灌砖。并且,他還支持更多的高級(jí)應(yīng)用傀蚌,比如:事務(wù)基显。

mysql 數(shù)據(jù)庫引擎: http://www.cnblogs.com/0201zcr/p/5296843.html
MySQL存儲(chǔ)引擎--MyISAM與InnoDB區(qū)別: https://segmentfault.com/a/1190000008227211

網(wǎng)絡(luò)

1 三次握手

  1. 客戶端通過向服務(wù)器端發(fā)送一個(gè)SYN來創(chuàng)建一個(gè)主動(dòng)打開,作為三次握手的一部分善炫×糜模客戶端把這段連接的序號(hào)設(shè)定為隨機(jī)數(shù) A。
  2. 服務(wù)器端應(yīng)當(dāng)為一個(gè)合法的SYN回送一個(gè)SYN/ACK箩艺。ACK 的確認(rèn)碼應(yīng)為 A+1窜醉,SYN/ACK 包本身又有一個(gè)隨機(jī)序號(hào) B。
  3. 最后艺谆,客戶端再發(fā)送一個(gè)ACK榨惰。當(dāng)服務(wù)端受到這個(gè)ACK的時(shí)候,就完成了三路握手静汤,并進(jìn)入了連接創(chuàng)建狀態(tài)琅催。此時(shí)包序號(hào)被設(shè)定為收到的確認(rèn)號(hào) A+1,而響應(yīng)則為 B+1虫给。

2 四次揮手

注意: 中斷連接端可以是客戶端藤抡,也可以是服務(wù)器端. 下面僅以客戶端斷開連接舉例, 反之亦然.

  1. 客戶端發(fā)送一個(gè)數(shù)據(jù)分段, 其中的 FIN 標(biāo)記設(shè)置為1. 客戶端進(jìn)入 FIN-WAIT 狀態(tài). 該狀態(tài)下客戶端只接收數(shù)據(jù), 不再發(fā)送數(shù)據(jù).
  2. 服務(wù)器接收到帶有 FIN = 1 的數(shù)據(jù)分段, 發(fā)送帶有 ACK = 1 的剩余數(shù)據(jù)分段, 確認(rèn)收到客戶端發(fā)來的 FIN 信息.
  3. 服務(wù)器等到所有數(shù)據(jù)傳輸結(jié)束, 向客戶端發(fā)送一個(gè)帶有 FIN = 1 的數(shù)據(jù)分段, 并進(jìn)入 CLOSE-WAIT 狀態(tài), 等待客戶端發(fā)來帶有 ACK = 1 的確認(rèn)報(bào)文.
  4. 客戶端收到服務(wù)器發(fā)來帶有 FIN = 1 的報(bào)文, 返回 ACK = 1 的報(bào)文確認(rèn), 為了防止服務(wù)器端未收到需要重發(fā), 進(jìn)入 TIME-WAIT 狀態(tài). 服務(wù)器接收到報(bào)文后關(guān)閉連接. 客戶端等待 2MSL 后未收到回復(fù), 則認(rèn)為服務(wù)器成功關(guān)閉, 客戶端關(guān)閉連接.

圖解: http://blog.csdn.net/whuslei/article/details/6667471

3 ARP協(xié)議

地址解析協(xié)議(Address Resolution Protocol),其基本功能為透過目標(biāo)設(shè)備的IP地址抹估,查詢目標(biāo)的MAC地址杰捂,以保證通信的順利進(jìn)行。它是IPv4網(wǎng)絡(luò)層必不可少的協(xié)議棋蚌,不過在IPv6中已不再適用嫁佳,并被鄰居發(fā)現(xiàn)協(xié)議(NDP)所替代。

4 urllib和urllib2的區(qū)別

這個(gè)面試官確實(shí)問過,當(dāng)時(shí)答的urllib2可以Post而urllib不可以.

  1. urllib提供urlencode方法用來GET查詢字符串的產(chǎn)生谷暮,而urllib2沒有蒿往。這是為何urllib常和urllib2一起使用的原因。
  2. urllib2可以接受一個(gè)Request類的實(shí)例來設(shè)置URL請(qǐng)求的headers湿弦,urllib僅可以接受URL瓤漏。這意味著,你不可以偽裝你的User Agent字符串等颊埃。

5 Post和Get

GET和POST有什么區(qū)別蔬充?及為什么網(wǎng)上的多數(shù)答案都是錯(cuò)的
知乎回答

get: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1
post: RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1

6 Cookie和Session

Cookie Session
儲(chǔ)存位置 客戶端 服務(wù)器端
目的 跟蹤會(huì)話,也可以保存用戶偏好設(shè)置或者保存用戶名密碼等 跟蹤會(huì)話
安全性 不安全 安全

session技術(shù)是要使用到cookie的班利,之所以出現(xiàn)session技術(shù)饥漫,主要是為了安全。

7 apache和nginx的區(qū)別

nginx 相對(duì) apache 的優(yōu)點(diǎn):

  • 輕量級(jí)罗标,同樣起web 服務(wù)庸队,比apache 占用更少的內(nèi)存及資源
  • 抗并發(fā),nginx 處理請(qǐng)求是異步非阻塞的闯割,支持更多的并發(fā)連接彻消,而apache 則是阻塞型的,在高并發(fā)下nginx 能保持低資源低消耗高性能
  • 配置簡(jiǎn)潔
  • 高度模塊化的設(shè)計(jì)宙拉,編寫模塊相對(duì)簡(jiǎn)單
  • 社區(qū)活躍

apache 相對(duì)nginx 的優(yōu)點(diǎn):

  • rewrite 宾尚,比nginx 的rewrite 強(qiáng)大
  • 模塊超多,基本想到的都可以找到
  • 少bug 谢澈,nginx 的bug 相對(duì)較多
  • 超穩(wěn)定

8 網(wǎng)站用戶密碼保存

  1. 明文保存
  2. 明文hash后保存,如md5
  3. MD5+Salt方式,這個(gè)salt可以隨機(jī)
  4. 知乎使用了Bcrypy(好像)加密

9 HTTP和HTTPS

狀態(tài)碼 定義
1xx 報(bào)告 接收到請(qǐng)求煌贴,繼續(xù)進(jìn)程
2xx 成功 步驟成功接收,被理解澳化,并被接受
3xx 重定向 為了完成請(qǐng)求,必須采取進(jìn)一步措施
4xx 客戶端出錯(cuò) 請(qǐng)求包括錯(cuò)的順序或不能完成
5xx 服務(wù)器出錯(cuò) 服務(wù)器無法完成顯然有效的請(qǐng)求

403: Forbidden
404: Not Found

HTTPS握手,對(duì)稱加密,非對(duì)稱加密,TLS/SSL,RSA

10 XSRF和XSS

  • CSRF(Cross-site request forgery)跨站請(qǐng)求偽造
  • XSS(Cross Site Scripting)跨站腳本攻擊

CSRF重點(diǎn)在請(qǐng)求,XSS重點(diǎn)在腳本

12 RESTful架構(gòu)(SOAP,RPC)

推薦: http://www.ruanyifeng.com/blog/2011/09/restful.html

15 CGI和WSGI

CGI是通用網(wǎng)關(guān)接口崔步,是連接web服務(wù)器和應(yīng)用程序的接口,用戶通過CGI來獲取動(dòng)態(tài)數(shù)據(jù)或文件等缎谷。
CGI程序是一個(gè)獨(dú)立的程序井濒,它可以用幾乎所有語言來寫,包括perl列林,c瑞你,lua,python等等希痴。

WSGI, Web Server Gateway Interface者甲,是Python應(yīng)用程序或框架和Web服務(wù)器之間的一種接口,WSGI的其中一個(gè)目的就是讓用戶可以用統(tǒng)一的語言(Python)編寫前后端砌创。

官方說明:PEP-3333

18 socket

推薦: http://www.360doc.com/content/11/0609/15/5482098_122692444.shtml

Socket=Ip address+ TCP/UDP + port

19 瀏覽器緩存

推薦: http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html

304 Not Modified

20 HTTP1.0和HTTP1.1

推薦: http://blog.csdn.net/elifefly/article/details/3964766

  1. 請(qǐng)求頭Host字段,一個(gè)服務(wù)器多個(gè)網(wǎng)站
  2. 長鏈接
  3. 文件斷點(diǎn)續(xù)傳
  4. 身份認(rèn)證,狀態(tài)管理,Cache緩存

HTTP請(qǐng)求8種方法介紹
HTTP/1.1協(xié)議中共定義了8種HTTP請(qǐng)求方法虏缸,HTTP請(qǐng)求方法也被叫做“請(qǐng)求動(dòng)作”鲫懒,不同的方法規(guī)定了不同的操作指定的資源方式。服務(wù)端也會(huì)根據(jù)不同的請(qǐng)求方法做不同的響應(yīng)刽辙。

GET

GET請(qǐng)求會(huì)顯示請(qǐng)求指定的資源窥岩。一般來說GET方法應(yīng)該只用于數(shù)據(jù)的讀取黔夭,而不應(yīng)當(dāng)用于會(huì)產(chǎn)生副作用的非冪等的操作中库菲。

GET會(huì)方法請(qǐng)求指定的頁面信息,并返回響應(yīng)主體剥槐,GET被認(rèn)為是不安全的方法慨灭,因?yàn)镚ET方法會(huì)被網(wǎng)絡(luò)蜘蛛等任意的訪問朦乏。

HEAD

HEAD方法與GET方法一樣,都是向服務(wù)器發(fā)出指定資源的請(qǐng)求氧骤。但是呻疹,服務(wù)器在響應(yīng)HEAD請(qǐng)求時(shí)不會(huì)回傳資源的內(nèi)容部分,即:響應(yīng)主體语淘。這樣诲宇,我們可以不傳輸全部?jī)?nèi)容的情況下,就可以獲取服務(wù)器的響應(yīng)頭信息惶翻。HEAD方法常被用于客戶端查看服務(wù)器的性能姑蓝。

POST

POST請(qǐng)求會(huì) 向指定資源提交數(shù)據(jù),請(qǐng)求服務(wù)器進(jìn)行處理吕粗,如:表單數(shù)據(jù)提交纺荧、文件上傳等,請(qǐng)求數(shù)據(jù)會(huì)被包含在請(qǐng)求體中颅筋。POST方法是非冪等的方法宙暇,因?yàn)檫@個(gè)請(qǐng)求可能會(huì)創(chuàng)建新的資源或/和修改現(xiàn)有資源。

PUT

PUT請(qǐng)求會(huì)身向指定資源位置上傳其最新內(nèi)容议泵,PUT方法是冪等的方法占贫。通過該方法客戶端可以將指定資源的最新數(shù)據(jù)傳送給服務(wù)器取代指定的資源的內(nèi)容。

DELETE

DELETE請(qǐng)求用于請(qǐng)求服務(wù)器刪除所請(qǐng)求URI(統(tǒng)一資源標(biāo)識(shí)符先口,Uniform Resource Identifier)所標(biāo)識(shí)的資源型奥。DELETE請(qǐng)求后指定資源會(huì)被刪除,DELETE方法也是冪等的碉京。

CONNECT

CONNECT方法是HTTP/1.1協(xié)議預(yù)留的厢汹,能夠?qū)⑦B接改為管道方式的代理服務(wù)器。通常用于SSL加密服務(wù)器的鏈接與非加密的HTTP代理服務(wù)器的通信谐宙。

OPTIONS

OPTIONS請(qǐng)求與HEAD類似烫葬,一般也是用于客戶端查看服務(wù)器的性能。 這個(gè)方法會(huì)請(qǐng)求服務(wù)器返回該資源所支持的所有HTTP請(qǐng)求方法,該方法會(huì)用’*’來代替資源名稱搭综,向服務(wù)器發(fā)送OPTIONS請(qǐng)求垢箕,可以測(cè)試服務(wù)器功能是否正常。JavaScript的XMLHttpRequest對(duì)象進(jìn)行CORS跨域資源共享時(shí)兑巾,就是使用OPTIONS方法發(fā)送嗅探請(qǐng)求舰讹,以判斷是否有對(duì)指定資源的訪問權(quán)限。 允許

TRACE

TRACE請(qǐng)求服務(wù)器回顯其收到的請(qǐng)求信息闪朱,該方法主要用于HTTP請(qǐng)求的測(cè)試或診斷。

HTTP/1.1之后增加的方法

在HTTP/1.1標(biāo)準(zhǔn)制定之后钻洒,又陸續(xù)擴(kuò)展了一些方法奋姿。其中使用中較多的是 PATCH 方法:

PATCH

PATCH方法出現(xiàn)的較晚,它在2010年的RFC 5789標(biāo)準(zhǔn)中被定義素标。PATCH請(qǐng)求與PUT請(qǐng)求類似称诗,同樣用于資源的更新。二者有以下兩點(diǎn)不同:

但PATCH一般用于資源的部分更新头遭,而PUT一般用于資源的整體更新寓免。
當(dāng)資源不存在時(shí),PATCH會(huì)創(chuàng)建一個(gè)新的資源计维,而PUT只會(huì)對(duì)已在資源進(jìn)行更新袜香。

編程題

1 列表復(fù)制問題

list1=[None,None]
list2=list1*2 -->[None,None,None,None]
list3=[list1]*2 -->[[None,None],[None,None]]

2 求列表第三大的那個(gè)值

import random
b = [random.randint(1,10000) for i in range(1000)]
max1 = b[0]
max2 = b[1]
max3 = b[2]
for k in b:
    if k>max1:
        max1,max2,max3 = k,max1,max2
    if k>max3 and k<max2:
        max3 = k
    if k>max2 and k<max1:
        max3 = max2
        max2 = k
print('{0},{1},{2}'.format(max1,max2,max3))

3 實(shí)現(xiàn)一個(gè)隊(duì)列

參考博客園

# 首先獲取節(jié)點(diǎn),包含next指針和該節(jié)點(diǎn)位置上元素的值
class Node(object):
    def __init__(self, val):
        self.next = None
        self.val = val


class Queue(object):
    def __init__(self):
        self.first = None
        self.last = None

    # 進(jìn)隊(duì)操作
    def enter(self, n):
        # 實(shí)例節(jié)點(diǎn)
        n = Node(n)
        # 進(jìn)隊(duì)之前先判斷隊(duì)列是否為空鲫惶,即判斷first是否為None
        if self.first == None:
            # 此時(shí)last==first==n
            self.first = n
            self.last = self.first
        else:
            # 將last的指針設(shè)置為n蜈首,值設(shè)置為n
            self.last.next = n
            self.last = n

    # 出隊(duì)
    def quit(self):
        if self.first == None:
            return None
        else:
            tmp = self.first.val
            self.first = self.first.next
        return tmp

    # 保存隊(duì)列元素到列表
    def allQuit(self):
        Lists = []
        while self.first != None:
            Lists.append(self.first.val)
            self.first = self.first.next
        return Lists


if __name__ == '__main__':
    q = Queue()
    q.enter(1)
    q.enter(2)
    q.enter(3)
    # print(q.quit())
    # print(q.quit())
    # print(q.quit())
    # print(q.quit())

    print(q.allQuit())

4 實(shí)現(xiàn)一個(gè)堆棧

參考

class Stack(object):
    def __init__(self):
        self.top = None

    # 獲取棧頂?shù)闹?    def peek(self):
        if self.top != None:
            return self.top.val
        else:
            return None

    # 入棧操作
    def push(self, n):
        n = Node(n)  # 實(shí)例化節(jié)點(diǎn)
        n.next = self.top
        self.top = n
        return n.val

    # 出棧操作
    def pop(self):
        if self.top == None:
            return None
        else:
            tmp = self.top.val
            # return self.top.val
            self.top = self.top.next  # 棧頂元素下移一位
            return tmp
if __name__ == '__main__':
    s = Stack()
    # s.peek()
    s.push(1)
    print(s.peek())
    s.push(2)
    print(s.peek())
    s.push(3)
    print(s.peek())
    print(s.pop())
    print(s.pop())
    print(s.pop())
    print(s.pop())           

5 用Python實(shí)現(xiàn)一個(gè)單向鏈表

參考

"""節(jié)點(diǎn)類"""


class Node(object):
    def __init__(self, data):
        self.data = data
        self.nex = None

def __init__(self):
    """初始化鏈表"""
    self.head = None

def __len__(self):
    pre = self.head
    length = 0
    while pre:
        length += 1
        pre = pre.nex
    return length

"""追加節(jié)點(diǎn)"""

def append(self, data):
    """
    1.head 為none :head-->node
    2.tail.nex-->node
    :param data:
    :return:
    """
    node = Node(data)
    if self.head is None:
        self.head = node
    else:
        pre = self.head
        while pre.nex:
            pre = pre.nex
        pre.nex = node
# 獲取節(jié)點(diǎn)
def get(self, index):
    """
    :param index:
    :return:
    """
    index = index if index >= 0 else len(self) + index
    if len(self) < index or index < 0:
        return None
    pre = self.head
    while index:
        pre = pre.nex
        index -= 1
    return pre
"""設(shè)置節(jié)點(diǎn)"""

def set(self, index, data):
    node = self.get(index)
    if node:
        node.data = data
    return node
"""插入節(jié)點(diǎn)"""

def insert(self, index, data):
    """
    1.index 插入節(jié)點(diǎn)位置包括正負(fù)數(shù)
    2.找到index-1-->pre_node的節(jié)點(diǎn)
    3.pre_node.next-->node
      node.next-->pre_node.next.next
    4.head
    :param index:
    :param data:
    :return:
    """
    node = Node(data)
    if abs(index + 1) > len(self):
        return False
    index = index if index >= 0 else len(self) + index + 1
    if index == 0:
        node.nex = self.head
        self.head = node
    else:
        pre = self.get(index - 1)
        if pre:
            nex = pre.nex
            pre.nex = node
            node.nex = nex
        else:
            return False
    return node
"""刪除某個(gè)元素"""

def delete(self, index):
    f = index if index > 0 else abs(index + 1)
    if len(self) <= f:
        return False
    pre = self.head
    index = index if index >= 0 else len(self) + index
    prep = None
    while index:
        prep = pre
        pre = pre.nex
        index -= 1
    if not prep:
        self.head = pre.nex
    else:
        prep.nex = pre.nex
    return pre.data
"""反轉(zhuǎn)鏈表"""

def __reversed__(self):
    """
    1.pre-->next 轉(zhuǎn)變?yōu)?next-->pre
    2.pre 若是head 則把 pre.nex --> None
    3.tail-->self.head
    :return:
    """

    def reverse(pre_node, node):
        if pre_node is self.head:
            pre_node.nex = None
        if node:
            next_node = node.nex
            node.nex = pre_node
            return reverse(node, next_node)
        else:
            self.head = pre_node

    return reverse(self.head, self.head.nex)
"""清空鏈表"""

def clear(self):
    self.head = None

6 用Python實(shí)現(xiàn)一個(gè)雙向鏈表

參考
參考原文 代碼省略

7 臺(tái)階問題/斐波那契

一只青蛙一次可以跳上1級(jí)臺(tái)階,也可以跳上2級(jí)欠母。求該青蛙跳上一個(gè)n級(jí)的臺(tái)階總共有多少種跳法欢策。

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

8 變態(tài)臺(tái)階問題

一只青蛙一次可以跳上1級(jí)臺(tái)階,也可以跳上2級(jí)……它也可以跳上n級(jí)赏淌。求該青蛙跳上一個(gè)n級(jí)的臺(tái)階總共有多少種跳法踩寇。

fib = lambda n: n if n < 2 else 2 * fib(n - 1)

9 去除列表中的重復(fù)元素

用集合

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

列表推導(dǎo)式

l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]
for i in l1:
   if i not in l2:
       l2.append(i)

sorted排序并且用列表推導(dǎo)式.

l = ['b','c','d','b','c','a','a']
[single.append(i) for i in sorted(l) if i not in single]
print single

10 創(chuàng)建字典的方法

1 直接創(chuàng)建

dict = {'name':'earth', 'port':'80'}

2 工廠方法

items=[('name','earth'),('port','80')]
dict2=dict(items)
dict1=dict((['name','earth'],['port','80']))

3 fromkeys()方法

dict1={}.fromkeys(('x','y'),-1)
dict={'x':-1,'y':-1}
dict2={}.fromkeys(('x','y'))
dict2={'x':None, 'y':None}

11 合并兩個(gè)有序列表

知乎遠(yuǎn)程面試要求編程

尾遞歸

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, [])

循環(huán)算法

思路:

定義一個(gè)新的空列表

比較兩個(gè)列表的首個(gè)元素

小的就插入到新列表里

把已經(jīng)插入新列表的元素從舊列表刪除

直到兩個(gè)舊列表有一個(gè)為空

再把舊列表加到新列表后面

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

pop彈出

a = [1,2,3,7]
b = [3,4,5]

def merge_sortedlist(a,b):
    c = []
    while a and b:
        if a[0] >= b[0]:
            c.append(b.pop(0))
        else:
            c.append(a.pop(0))
    while a:
        c.append(a.pop(0))
    while b:
        c.append(b.pop(0))
    return c
print merge_sortedlist(a,b)

12 歸并排序

def merge(a, b):
    c = []
    h = j = 0
    # 依次便利,拿到兩個(gè)數(shù)組更小的元素六水,
    while j < len(a) and h < len(b):
        # 如果0索引位置的元素a更小俺孙,添加a[0]到c,再將a[1]與b[0]比較缩擂,依次類推鼠冕,剩余最后的元素就是兩個(gè)數(shù)組的最大值
        if a[j] < b[h]:
            c.append(a[j])
            j += 1
        else:
            c.append(b[h])
            h += 1

    if j == len(a):
        for i in b[h:]:
            c.append(i)
    else:
        for i in a[j:]:
            c.append(i)

    return c


def merge_sort(lists):
    if len(lists) <= 1:
        return lists
    middle = len(lists)//2
    left = merge_sort(lists[:middle])
    right = merge_sort(lists[middle:])
    return merge(left, right)

if __name__ == '__main__':
    a = [4, 7, 8, 3, 5, 9,10]
    print(merge_sort(a))

13 質(zhì)數(shù)和日期問題

class PrimeNumbers(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def isPrimeNumber(self, k):
        if k < 2:
            return False
        for i in range(2, k):
            if k % i == 0:
                return False
        return True

    def __iter__(self):
        for k in range(self.start, self.end + 1):
            if self.isPrimeNumber(k):
                yield k


#print(isinstance(PrimeNumbers(1,100)))


if __name__ == '__main__':
    a = PrimeNumbers(1, 100)
    f = a.__iter__()
    L = []
    for i in f:
        L.append(i)
    print(L)

# 寫一個(gè)函數(shù),計(jì)算給定日期是該年的第幾天和周數(shù)
def count(year,month,day):
    count=0
    if (year%4==0 and year%100!=0) or year%400==0:
        print('%d年是閏年胯盯,2月份有29天懈费!'%year)
        list1=[31,29,31,30,31,30,31,31,30,31,30,31]
        for i in range(month-1):
            count=count+list1[i]
        return count+
    else:
        print('%d年是平年,2月份有29天博脑!' % year)
        li2 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        for i in range(month-1):
            count +=li2[i]
        return count+day
if __name__ == "__main__":
    year = int(input('請(qǐng)輸入年份:'))
    month = int(input('請(qǐng)輸入月份:'))
    day = int(input('請(qǐng)輸入日期:'))
    count = count(year,month,day)
    print('%d年%d月%d日是今年的第%d天憎乙!'%(year,month,day,count))

14 二分查找


#coding:utf-8
def binary_search(list,item):
    low = 0
    high = len(list)-1
    while low<=high:
        mid = (low+high)/2
        guess = list[mid]
        if guess>item:
            high = mid-1
        elif guess<item:
            low = mid+1
        else:
            return mid
    return None
mylist = [1,3,5,7,9]
print binary_search(mylist,3)

參考: http://blog.csdn.net/u013205877/article/details/76411718

15 打印文件夾

def print_directory_contents(sPath):
    """
    這個(gè)函數(shù)接受文件夾的名稱作為輸入?yún)?shù)票罐,
    返回該文件夾中文件的路徑,
    以及其包含文件夾中文件的路徑泞边。

    """
    import os                                       
    for sChild in os.listdir(sPath):                
        sChildPath = os.path.join(sPath,sChild)
        if os.path.isdir(sChildPath):
            print_directory_contents(sChildPath)
        else:
            print sChildPath

16 找零問題


#coding:utf-8
#values是硬幣的面值values = [ 25, 21, 10, 5, 1]
#valuesCounts   錢幣對(duì)應(yīng)的種類數(shù)
#money  找出來的總錢數(shù)
#coinsUsed   對(duì)應(yīng)于目前錢幣總數(shù)i所使用的硬幣數(shù)目

def coinChange(values,valuesCounts,money,coinsUsed):
    #遍歷出從1到money所有的錢數(shù)可能
    for cents in range(1,money+1):
        minCoins = cents
        #把所有的硬幣面值遍歷出來和錢數(shù)做對(duì)比
        for kind in range(0,valuesCounts):
            if (values[kind] <= cents):
                temp = coinsUsed[cents - values[kind]] +1
                if (temp < minCoins):
                    minCoins = temp
        coinsUsed[cents] = minCoins
        print ('面值:{0}的最少硬幣使用數(shù)為:{1}'.format(cents, coinsUsed[cents]))

思路: http://blog.csdn.net/wdxin1322/article/details/9501163

方法: http://www.cnblogs.com/ChenxofHit/archive/2011/03/18/1988431.html

17 二叉樹節(jié)點(diǎn)


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)))

17 前中后序遍歷

深度遍歷改變順序就OK了


#coding:utf-8
#二叉樹的遍歷
#簡(jiǎn)單的二叉樹節(jié)點(diǎn)類
class Node(object):
    def __init__(self,value,left,right):
        self.value = value
        self.left = left
        self.right = right

#中序遍歷:遍歷左子樹,訪問當(dāng)前節(jié)點(diǎn),遍歷右子樹

def mid_travelsal(root):
    if root.left is None:
        mid_travelsal(root.left)
    #訪問當(dāng)前節(jié)點(diǎn)
    print(root.value)
    if root.right is not None:
        mid_travelsal(root.right)

#前序遍歷:訪問當(dāng)前節(jié)點(diǎn),遍歷左子樹,遍歷右子樹

def pre_travelsal(root):
    print (root.value)
    if root.left is not None:
        pre_travelsal(root.left)
    if root.right is not None:
        pre_travelsal(root.right)

#后續(xù)遍歷:遍歷左子樹,遍歷右子樹,訪問當(dāng)前節(jié)點(diǎn)

def post_trvelsal(root):
    if root.left is not None:
        post_trvelsal(root.left)
    if root.right is not None:
        post_trvelsal(root.right)
    print (root.value)

18 求最大樹深

def maxDepth(root):
        if not root:
            return 0
        return max(maxDepth(root.left), maxDepth(root.right)) + 1

19 求兩棵樹是否相同

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

20 前序中序求后序

推薦: 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

21 廣度遍歷和深度遍歷二叉樹

給定一個(gè)數(shù)組该押,構(gòu)建二叉樹,并且按層次打印這個(gè)二叉樹

22 快排

#coding:utf-8
def quicksort(list):
    if len(list)<2:
        return list
    else:
        midpivot = list[0]
        lessbeforemidpivot = [i for i in list[1:] if i<=midpivot]
        biggerafterpivot = [i for i in list[1:] if i > midpivot]
        finallylist = quicksort(lessbeforemidpivot)+[midpivot]+quicksort(biggerafterpivot)
        return finallylist

print quicksort([2,4,6,7,1,2,5])

# 使用lambda函數(shù)實(shí)現(xiàn)
quicksort=lambda data:data if len(data)<2 else quicksort([item for item in data[1:] if item<=data[0]])+[data[0]]+quicksort([item for item in data[1:] if item>data[0]])

print quicksort([2,4,6,7,1,2,5])

更多排序問題可見:數(shù)據(jù)結(jié)構(gòu)與算法-排序篇-Python描述

23 層次遍歷


def lookup(root):
    row = [root]
    while row:
        print(row)
        row = [kid for item in row for kid in (item.left, item.right) if kid]

24 深度遍歷


def deep(root):
    if not root:
        return
    print root.data
    deep(root.left)
    deep(root.right)

if __name__ == '__main__':
    lookup(tree)
    deep(tree)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阵谚,一起剝皮案震驚了整個(gè)濱河市蚕礼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梢什,老刑警劉巖奠蹬,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嗡午,居然都是意外死亡囤躁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門荔睹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狸演,“玉大人,你說我怎么就攤上這事僻他∠啵” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵中姜,是天一觀的道長消玄。 經(jīng)常有香客問我,道長丢胚,這世上最難降的妖魔是什么翩瓜? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮携龟,結(jié)果婚禮上兔跌,老公的妹妹穿的比我還像新娘。我一直安慰自己峡蟋,他們只是感情好坟桅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蕊蝗,像睡著了一般仅乓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蓬戚,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天夸楣,我揣著相機(jī)與錄音,去河邊找鬼。 笑死豫喧,一個(gè)胖子當(dāng)著我的面吹牛石洗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播紧显,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼讲衫,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了孵班?” 一聲冷哼從身側(cè)響起涉兽,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎篙程,沒想到半個(gè)月后花椭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡房午,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丹允。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郭厌。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雕蔽,靈堂內(nèi)的尸體忽然破棺而出折柠,到底是詐尸還是另有隱情,我是刑警寧澤批狐,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布扇售,位于F島的核電站,受9級(jí)特大地震影響嚣艇,放射性物質(zhì)發(fā)生泄漏承冰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一食零、第九天 我趴在偏房一處隱蔽的房頂上張望困乒。 院中可真熱鬧,春花似錦贰谣、人聲如沸娜搂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽百宇。三九已至,卻和暖如春秘豹,著一層夾襖步出監(jiān)牢的瞬間携御,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留因痛,地道東北人婚苹。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像鸵膏,于是被迫代替她去往敵國和親膊升。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容