BAT-Python面試題

Python語言特性
1 Python的函數參數傳遞
看兩個以下例子,分析運行結果:
代碼一:php

a = 1
def fun(a):
a = 2
fun(a)
print(a) # 1html

代碼二:前端

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

全部的變量均可以理解是內存中一個對象的「引用」,或者,也能夠看似c中void*的感受。
這裏記住的是類型是屬於對象的,而不是變量。而對象有兩種,「可更改」(mutable)與「不可更改」(immutable)對象。在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是能夠修改的對象。(這就是這個問題的重點)
當一個引用傳遞給函數的時候,函數自動複製一份引用,這個函數裏的引用和外邊的引用沒有半毛關係了.因此第一個例子裏函數把引用指向了一個不可變對象,當函數返回的時候,外面的引用沒半毛感受.而第二個例子就不同了,函數內的引用指向的是可變對象,對它的操做就和定位了指針地址同樣,在內存裏進行修改.
2 Python中的元類(metaclass)
元類就是用來建立類的「東西」。你建立類就是爲了建立類的實例對象,可是咱們已經學習到了Python中的類也是對象。好吧,元類就是用來建立這些類(對象)的,元類就是類的類
這個很是的不經常使用,詳情請看:《深入理解Python中的元類(metaclass)》
3 @staticmethod和@classmethod
Python其實有3個方法,即靜態方法(staticmethod),類方法(classmethod)和實例方法,以下:
 
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(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)
4 類變量和實例變量node

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了.
能夠看看下面的例子:python

class Person:

    name=[]
 
p1=Person()
p2=Person()
p1.name.append(1)
print(p1.name)  # [1]
print(p2.name)  # [1]
print(Person.name)  # [1]
5 Python自省
這個也是python彪悍的特性.
自省就是面向對象的語言所寫的程序在運行時,所能知道對象的類型.簡單一句就是運行時可以得到對象的類型.好比type(),dir(),getattr(),hasattr(),isinstance().
6 字典推導式
可能你見過列表推導時,卻沒有見過字典推導式,在2.7中才加入的:
d = {key: value for (key, value) in iterable}mysql

7 Python中單下劃線和雙下劃線nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14 >>> class MyClass():
...     def init(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...git

mc = MyClass()
print(mc.__superprivate)
Traceback (most recent call last):
  File " ", line 1, in
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
8 字符串格式化:%和.format
.format在許多方面看起來更便利.對於%最煩人的是它沒法同時傳遞一個變量和元組.你可能會想下面的代碼不會有什麼問題:
Python:
"hi there %s" % name
可是,若是name剛好是(1,2,3),它將會拋出一個TypeError異常.爲了保證它老是正確的,你必須這樣作:
"hi there %s" % (name,)   # 提供一個單元素的數組而不是一個參數
9 迭代器和生成器
在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。
能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。
程序員

這個是stackoverflow裏python排名第一的問題,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python
10 *args and **kwargs
用*args和**kwargs只是爲了方便並無強制使用它們.
當你不肯定你的函數裏將要傳遞多少參數時你能夠用*args.例如,它能夠傳遞任意數量的參數:

1
2
3
4
5
6
7
8 >>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print '{0}. {1}'.format(count, thing)
...

print_everything('apple', 'banana', 'cabbage')

  1. apple
  2. banana
  3. cabbage
    類似的,**kwargs容許你使用沒有事先定義的參數名:

1
2
3
4
5
6
7 >>> 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.命名參數在列表的最前端.例如:

1 def table_things(titlestring, **kwargs)
*args和**kwargs能夠同時在函數的定義中,可是*args必須在**kwargs前面.
當調用函數時你也能夠用*和**語法.例如:

1
2
3
4
5
6
7 >>> 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
11 面向切面編程AOP和裝飾器
這個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
12 鴨子類型
「當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就能夠被稱爲鴨子。」
咱們並不關心對象是什麼類型,究竟是不是鴨子,只關心行爲。
好比在python中,有不少file-like的東西,好比StringIO,GzipFile,socket。它們有不少相同的方法,咱們把它們看成文件使用。
又好比list.extend()方法中,咱們並不關心它的參數是否是list,只要它是可迭代的,因此它的參數能夠是list/tuple/dict/字符串/生成器等.
鴨子類型在動態語言中常用,很是靈活,使得python不想java那樣專門去弄一大堆的設計模式。
13 Python中重載
引自知乎:http://www.zhihu.com/question/20053359
函數重載主要是爲了解決兩個問題。
1.可變參數類型。
2.可變參數個數。
另外,一個基本的設計原則是,僅僅當兩個函數除了參數類型和參數個數不一樣之外,其功能是徹底相同的,此時才使用函數重載,若是兩個函數的功能其實不一樣,那麼不該當使用重載,而應當使用一個名字不一樣的函數。
好吧,那麼對於狀況 1 ,函數功能相同,可是參數類型不一樣,python 如何處理?答案是根本不須要處理,由於 python 能夠接受任何類型的參數,若是函數的功能相同,那麼不一樣的參數類型在 python 中極可能是相同的代碼,沒有必要作成兩個不一樣函數。
那麼對於狀況 2 ,函數功能相同,但參數個數不一樣,python 如何處理?你們知道,答案就是缺省參數。對那些缺乏的參數設定爲缺省參數便可解決問題。由於你假設函數功能相同,那麼那些缺乏的參數終歸是須要用的。
好了,鑑於狀況 1 跟 狀況 2 都有了解決方案,python 天然就不須要函數重載了。
14 新式類和舊式類
這個面試官問了,我說了老半天,不知道他問的真正意圖是什麼.
這篇文章很好的介紹了新式類的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html
新式類很早在2.2就出現了,因此舊式類徹底是兼容的問題,Python3裏的類所有都是新式類.這裏有一個MRO問題能夠了解下(新式類是廣度優先,舊式類是深度優先), 裏講的也不少.
15 __new__和__init__的區別
這個__new__確實不多見到,先作了解吧.
1.__new__是一個靜態方法,而__init__是一個實例方法.
2.__new__方法會返回一個建立的實例,而__init__什麼都不返回.
3.只有在__new__返回一個cls的實例時後面的__init__才能被調用.
4.當建立一個新實例時調用 new,初始化一個實例時用 init.
ps: __metaclass__是建立類時起做用.因此咱們能夠分別使用 metaclass,__new__和__init__來分別在類建立,實例建立和實例初始化的時候作一些小手腳.
16 單例模式
這個絕對常考啊.絕對要記住1~2個方法,當時面試官是讓手寫的.
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 共享屬性
建立實例時把全部實例的__dict__指向同一個字典,這樣它們具備相同的屬性和方法.
1
2
3
4
5
6
7
8
9 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 裝飾器版本

1
2
3
4
5
6
7
8
9
10
11 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:

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

17 Python中的做用域
Python 中,一個變量的做用域老是由在代碼中被賦值的地方所決定的。
當 Python 遇到一個變量的話他會按照這樣的順序進行搜索:
本地做用域(Local)→當前做用域被嵌入的本地做用域(Enclosing locals)→全局/模塊做用域(Global)→內置做用域(Built-in)
18 GIL線程全局鎖
線程全局鎖(Global Interpreter Lock),即Python爲了保證線程安全而採起的獨立線程運行的限制,說白了就是一個核只能在同一時間運行一個線程.
解決辦法就是多進程和下面的協程(協程也只是單CPU,可是能減少切換代價提高性能).
19 協程
簡單點說協程是進程和線程的升級版,進程和線程都面臨着內核態和用戶態的切換問題而耗費許多切換時間,而協程就是用戶本身控制切換的時機,再也不須要陷入系統的內核態.
Python裏最多見的yield就是協程的思想!能夠查看第九個問題.
20 閉包
閉包(closure)是函數式編程的重要的語法結構。閉包也是一種組織代碼的結構,它一樣提升了代碼的可重複使用性。
當一個內嵌函數引用其外部做做用域的變量,咱們就會獲得一個閉包. 總結一下,建立一個閉包必須知足如下幾點:
1.必須有一個內嵌函數
2.內嵌函數必須引用外部函數中的變量
3.外部函數的返回值必須是內嵌函數
感受閉包仍是有難度的,幾句話是說不明白的,仍是查查相關資料.
重點是函數運行後並不會被撤銷,就像16題的instance字典同樣,當函數運行完後,instance並不被銷燬,而是繼續留在內存空間裏.這個功能相似類裏的類變量,只不過遷移到了函數上.
閉包就像個空心球同樣,你知道外面和裏面,但你不知道中間是什麼樣.
21 lambda函數
其實就是一個匿名函數,爲何叫lambda?由於和後面的函數式編程有關.
22 Python函數式編程
這個須要適當的瞭解一下吧,畢竟函數式編程在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

23 Python裏的拷貝
引用和copy(),deepcopy()的區別
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 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']]
24 Python垃圾回收機制
Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,經過「標記-清除」(mark and sweep)解決容器對象可能產生的循環引用問題,經過「分代回收」(generation collection)以空間換時間的方法提升垃圾回收效率。
1 引用計數
PyObject是每一個對象必有的內容,其中ob_refcnt就是作爲引用計數。當一個對象有新的引用時,它的ob_refcnt就會增長,當引用它的對象被刪除,它的ob_refcnt就會減小.引用計數爲0時,該對象生命就結束了。
優勢:
1.簡單
2.實時性
缺點:
1.維護引用計數消耗資源
2.循環引用
2 標記-清除機制
基本思路是先按需分配,等到沒有空閒內存的時候從寄存器和程序棧上的引用出發,遍歷以對象爲節點、以引用爲邊構成的圖,把全部能夠訪問到的對象打上標記,而後清掃一遍內存空間,把全部沒標記的對象釋放。
3 分代技術
分代回收的總體思想是:將系統中的全部內存塊根據其存活時間劃分爲不一樣的集合,每一個集合就成爲一個「代」,垃圾收集頻率隨着「代」的存活時間的增大而減少,存活時間一般利用通過幾回垃圾回收來度量。
Python默認定義了三代對象集合,索引數越大,對象存活時間越長。
舉例:
當某些內存塊M通過了3次垃圾收集的清洗以後還存活時,咱們就將內存塊M劃到一個集合A中去,而新分配的內存都劃分到集合B中去。當垃圾收集開始工做時,大多數狀況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔至關長一段時間後才進行,這就使得垃圾收集機制須要處理的內存少了,效率天然就提升了。在這個過程當中,集合B中的某些內存塊因爲存活時間長而會被轉移到集合A中,固然,集合A中實際上也存在一些垃圾,這些垃圾的回收會由於這種分代的機制而被延遲。
25 Python裏面如何實現tuple和list的轉換?
答:tuple,能夠說是不可變的list,訪問方式仍是經過索引下標的方式。
當你明肯定義個tuple是,若是僅有一個元素,必須帶有,例如:(1,)。
固然,在2.7之後的版,python裏還增長了命名式的tuple!

至於有什麼用,首先第一點,樓主玩過python都知道,python的函數能夠有多返回值的,而python裏,多返回值,就是用tuple來表示,這是用的最廣的了,

好比說,你須要定義一個常量的列表,但你又不想使用list,那也能夠是要你管tuple,例如:
if a in ('A','B','C'):pass

26 Python的is
is是對比地址,==是對比值
27 read,readline和readlines
read 讀取整個文件
readline 讀取下一行,使用生成器方法
readlines 讀取整個文件到一個迭代器以供咱們遍歷
28 Python2和3的區別
大部分Python庫都同時支持Python 2.7.x和3.x版本的,因此不論選擇哪一個版本都是能夠的。但爲了在使用Python時避開某些版本中一些常見的陷阱,或須要移植某個Python項目
使用__future__模塊
print函數
整數除法
Unicode
xrange
觸發異常
處理異常
next()函數和.next()方法
For循環變量與全局命名空間泄漏
比較無序類型
使用input()解析輸入內容
返回可迭代對象,而不是列表

推薦:《Python 2.7.x 和 3.x 版本的重要區別》

29到底什麼是Python?你能夠在回答中與其餘技術進行對比
答案
下面是一些關鍵點:
Python是一種解釋型語言。這就是說,與C語言和C的衍生語言不一樣,Python代碼在運行以前不須要編譯。其餘解釋型語言還包括PHP和Ruby。
Python是動態類型語言,指的是你在聲明變量時,不須要說明變量的類型。你能夠直接編寫相似x=111和x="I'm a string"這樣的代碼,程序不會報錯。
Python很是適合面向對象的編程(OOP),由於它支持經過組合(composition)與繼承(inheritance)的方式定義類(class)。Python中沒有訪問說明符(access specifier,相似C++中的public和private),這麼設計的依據是「你們都是成年人了」。
在Python語言中,函數是第一類對象(first-class objects)。這指的是它們能夠被指定給變量,函數既能返回函數類型,也能夠接受函數做爲輸入。類(class)也是第一類對象。
Python代碼編寫快,可是運行速度比編譯語言一般要慢。好在Python容許加入基於C語言編寫的擴展,所以咱們可以優化代碼,消除瓶頸,這點一般是能夠實現的。numpy就是一個很好地例子,它的運行速度真的很是快,由於不少算術運算其實並非經過Python實現的。
Python用途很是普遍——網絡應用,自動化,科學建模,大數據應用,等等。它也常被用做「膠水語言」,幫助其餘語言和組件改善運行情況。
Python讓困難的事情變得容易,所以程序員能夠專一於算法和數據結構的設計,而不用處理底層的細節。
爲何提這個問題:
若是你應聘的是一個Python開發崗位,你就應該知道這是門什麼樣的語言,以及它爲何這麼酷。以及它哪裏很差。

30補充缺失的代碼
def print_directory_contents(sPath):
"""
這個函數接受文件夾的名稱做爲輸入參數,
返回該文件夾中文件的路徑,
以及其包含文件夾中文件的路徑。
"""
# 補充代碼
答案
def print_directory_contents(sPath):
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
特別要注意如下幾點:
命名規範要統一。若是樣本代碼中可以看出命名規範,遵循其已有的規範。
遞歸函數須要遞歸併終止。確保你明白其中的原理,不然你將面臨無休無止的調用棧(callstack)。
咱們使用os模塊與操做系統進行交互,同時作到交互方式是能夠跨平臺的。你能夠把代碼寫成sChildPath = sPath + '/' + sChild,可是這個在Windows系統上會出錯。
熟悉基礎模塊是很是有價值的,可是別想破腦殼都背下來,記住Google是你工做中的良師益友。
若是你不明白代碼的預期功能,就大膽提問。
堅持KISS原則!保持簡單,不過腦子就能懂!
爲何提這個問題:
說明面試者對與操做系統交互的基礎知識
遞歸真是太好用啦
31閱讀下面的代碼,寫出A0,A1至An的最終值。
A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
A1 = range(10)
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
A5 = {i:ii for i in A1}
A6 = [[i,i*i] for i in A1]
答案
A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4}
A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A2 = []
A3 = [1, 3, 2, 5, 4]
A4 = [1, 2, 3, 4, 5]
A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]
爲何提這個問題:
列表解析(list comprehension)十分節約時間,對不少人來講也是一個大的學習障礙。
若是你讀懂了這些代碼,就極可能能夠寫下正確地值。
其中部分代碼故意寫的怪怪的。由於你共事的人之中也會有怪人。
32下面代碼會輸出什麼:
def f(x,l=[]):
for i in range(x):
l.append(i
i)
print(l)

f(2)
f(3,[3,2,1])
f(3)
答案:
[0, 1]
[3, 2, 1, 0, 1, 4]
[0, 1, 0, 1, 4]
呃?
第一個函數調用十分明顯,for循環前後將0和1添加至了空列表l中。l是變量的名字,指向內存中存儲的一個列表。第二個函數調用在一塊新的內存中建立了新的列表。l這時指向了新生成的列表。以後再往新列表中添加0、1和4。很棒吧。第三個函數調用的結果就有些奇怪了。它使用了以前內存地址中存儲的舊列表。這就是爲何它的前兩個元素是0和1了。

33你如何管理不一樣版本的代碼?
答案:
版本管理!被問到這個問題的時候,你應該要表現得很興奮,甚至告訴他們你是如何使用Git(或是其餘你最喜歡的工具)追蹤本身和奶奶的書信往來。我偏向於使用Git做爲版本控制系統(VCS),但還有其餘的選擇,好比subversion(SVN)。
爲何提這個問題:
由於沒有版本控制的代碼,就像沒有杯子的咖啡。有時候咱們須要寫一些一次性的、能夠隨手扔掉的腳本,這種狀況下不做版本控制不要緊。可是若是你面對的是大量的代碼,使用版本控制系統是有利的。版本控制可以幫你追蹤誰對代碼庫作了什麼操做;發現新引入了什麼bug;管理你的軟件的不一樣版本和發行版;在團隊成員中分享源代碼;部署及其餘自動化處理。它能讓你回滾到出現問題以前的版本,單憑這點就特別棒了。還有其餘的好功能。怎麼一個棒字了得!
34「猴子補丁」(monkey patching)指的是什麼?這種作法好嗎?
答案:
「猴子補丁」就是指,在函數或對象已經定義以後,再去改變它們的行爲。
舉個例子:
import datetime
datetime.datetime.now = lambda: datetime.datetime(2012, 12, 12)
大部分狀況下,這是種很很差的作法 - 由於函數在代碼庫中的行爲最好是都保持一致。打「猴子補丁」的緣由多是爲了測試。mock包對實現這個目的頗有幫助。
爲何提這個問題?
答對這個問題說明你對單元測試的方法有必定了解。你若是提到要避免「猴子補丁」,能夠說明你不是那種喜歡花裏胡哨代碼的程序員(公司裏就有這種人,跟他們共事真是糟糕透了),而是更注重可維護性。還記得KISS原則碼?答對這個問題還說明你明白一些Python底層運做的方式,函數實際是如何存儲、調用等等。
另外:若是你沒讀過mock模塊的話,真的值得花時間讀一讀。這個模塊很是有用。

35閱讀下面的代碼,它的輸出結果是什麼?
class A(object):
def go(self):
print "go A go!"
def stop(self):
print "stop A stop!"
def pause(self):
raise Exception("Not Implemented")

class B(A):
def go(self):
super(B, self).go()
print "go B go!"

class C(A):
def go(self):
super(C, self).go()
print "go C go!"
def stop(self):
super(C, self).stop()
print "stop C stop!"

class D(B,C):
def go(self):
super(D, self).go()
print "go D go!"
def stop(self):
super(D, self).stop()
print "stop D stop!"
def pause(self):
print "wait D wait!"

class E(B,C): pass

a = A()
b = B()
c = C()
d = D()
e = E()

說明下列代碼的輸出結果

a.go()
b.go()
c.go()
d.go()
e.go()

a.stop()
b.stop()
c.stop()
d.stop()
e.stop()

a.pause()
b.pause()
c.pause()
d.pause()
e.pause()
答案
輸出結果以註釋的形式表示:
a.go()

go A go!

b.go()

go A go!

go B go!

c.go()

go A go!

go C go!

d.go()

go A go!

go C go!

go B go!

go D go!

e.go()

go A go!

go C go!

go B go!

a.stop()

stop A stop!

b.stop()

stop A stop!

c.stop()

stop A stop!

stop C stop!

d.stop()

stop A stop!

stop C stop!

stop D stop!

e.stop()

stop A stop!

a.pause()

... Exception: Not Implemented

b.pause()

... Exception: Not Implemented

c.pause()

... Exception: Not Implemented

d.pause()

wait D wait!

e.pause()

...Exception: Not Implemented

爲何提這個問題?
由於面向對象的編程真的真的很重要。不騙你。答對這道問題說明你理解了繼承和Python中super函數的用法。

36閱讀下面的代碼,它的輸出結果是什麼?
class Node(object):
def init(self,sName):
self._lChildren = []
self.sName = sName
def repr(self):
return "<Node '{}'>".format(self.sName)
def append(self,*args,**kwargs):
self._lChildren.append(*args,**kwargs)
def print_all_1(self):
print self
for oChild in self._lChildren:
oChild.print_all_1()
def print_all_2(self):
def gen(o):
lAll = [o,]
while lAll:
oNext = lAll.pop(0)
lAll.extend(oNext._lChildren)
yield oNext
for oNode in gen(self):
print oNode

oRoot = Node("root")
oChild1 = Node("child1")
oChild2 = Node("child2")
oChild3 = Node("child3")
oChild4 = Node("child4")
oChild5 = Node("child5")
oChild6 = Node("child6")
oChild7 = Node("child7")
oChild8 = Node("child8")
oChild9 = Node("child9")
oChild10 = Node("child10")

oRoot.append(oChild1)
oRoot.append(oChild2)
oRoot.append(oChild3)
oChild1.append(oChild4)
oChild1.append(oChild5)
oChild2.append(oChild6)
oChild4.append(oChild7)
oChild3.append(oChild8)
oChild3.append(oChild9)
oChild6.append(oChild10)

說明下面代碼的輸出結果

oRoot.print_all_1()
oRoot.print_all_2()
答案
oRoot.print_all_1()會打印下面的結果:
<Node 'root'>
<Node 'child1'>
<Node 'child4'>
<Node 'child7'>
<Node 'child5'>
<Node 'child2'>
<Node 'child6'>
<Node 'child10'>
<Node 'child3'>
<Node 'child8'>
<Node 'child9'>
oRoot.print_all_1()會打印下面的結果:
<Node 'root'>
<Node 'child1'>
<Node 'child2'>
<Node 'child3'>
<Node 'child4'>
<Node 'child5'>
<Node 'child6'>
<Node 'child8'>
<Node 'child9'>
<Node 'child7'>
<Node 'child10'>
爲何提這個問題?
由於對象的精髓就在於組合(composition)與對象構造(object construction)。對象須要有組合成分構成,並且得以某種方式初始化。這裏也涉及到遞歸和生成器(generator)的使用。
生成器是很棒的數據類型。你能夠只經過構造一個很長的列表,而後打印列表的內容,就能夠取得與print_all_2相似的功能。生成器還有一個好處,就是不用佔據不少內存。
有一點還值得指出,就是print_all_1會以深度優先(depth-first)的方式遍歷樹(tree),而print_all_2則是寬度優先(width-first)。有時候,一種遍歷方式比另外一種更合適。但這要看你的應用的具體狀況。

36.介紹一下except的用法和做用?
答:try…except…except…[else…][finally…]
執行try下的語句,若是引起異常,則執行過程會跳到except語句。對每一個except分支順序嘗試執行,若是引起的異常與except中的異常組匹配,執行相應的語句。若是全部的except都不匹配,則異常會傳遞到下一個調用本代碼的最高層try代碼中。
try下的語句正常執行,則執行else塊代碼。若是發生異常,就不會執行
若是存在finally語句,最後老是會執行。

37.Python中pass語句的做用是什麼?
答:pass語句不會執行任何操做,通常做爲佔位符或者建立佔位程序,whileFalse:pass
38.介紹一下Python下range()函數的用法?
答:列出一組數據,常常用在for in range()循環中

39.如何用Python來進行查詢和替換一個文本字符串?
答:能夠使用re模塊中的sub()函數或者subn()函數來進行查詢和替換,
格式:sub(replacement, string[,count=0])(replacement是被替換成的文本,string是須要被替換的文本,count是一個可選參數,指最大被替換的數量)

import re
p=re.compile(‘blue|white|red’)
print(p.sub(‘colour’,'blue socks and red shoes’))
colour socks and colourshoes
print(p.sub(‘colour’,'blue socks and red shoes’,count=1))
colour socks and redshoes
subn()方法執行的效果跟sub()同樣,不過它會返回一個二維數組,包括替換後的新的字符串和總共替換的數量

40.Python裏面match()和search()的區別?
答:re模塊中match(pattern,string[,flags]),檢查string的開頭是否與pattern匹配。
re模塊中research(pattern,string[,flags]),在string搜索pattern的第一個匹配值。

print(re.match(‘super’, ‘superstition’).span())
(0, 5)
print(re.match(‘super’, ‘insuperable’))
None
print(re.search(‘super’, ‘superstition’).span())
(0, 5)
print(re.search(‘super’, ‘insuperable’).span())
(2, 7)

41.用Python匹配HTML tag的時候,<.>和<.?>有什麼區別?
答:術語叫貪婪匹配( <.> )和非貪婪匹配(<.?> )
例如:
test
<.> :
test
<.
?> :

42.Python裏面如何生成隨機數?
答:random模塊
隨機整數:random.randint(a,b):返回隨機整數x,a<=x<=b
random.randrange(start,stop,[,step]):返回一個範圍在(start,stop,step)之間的隨機整數,不包括結束值。
隨機實數:random.random( ):返回0到1之間的浮點數
random.uniform(a,b):返回指定範圍內的浮點數。

43.有沒有一個工具能夠幫助查找python的bug和進行靜態的代碼分析?
答:PyChecker是一個python代碼的靜態分析工具,它能夠幫助查找python代碼的bug, 會對代碼的複雜度和格式提出警告
Pylint是另一個工具能夠進行codingstandard檢查

44.如何在一個function裏面設置一個全局的變量?
答:解決方法是在function的開始插入一個global聲明:
def f()
global x

45.單引號,雙引號,三引號的區別
答:單引號和雙引號是等效的,若是要換行,須要符號(),三引號則能夠直接換行,而且能夠包含註釋
若是要表示Let’s go 這個字符串
單引號:s4 = ‘Let’s go’
雙引號:s5 = 「Let’s go」
s6 = ‘I realy like「python」!’
這就是單引號和雙引號均可以表示字符串的緣由了

46 Python和多線程(multi-threading)。這是個好主意碼?列舉一些讓Python代碼以並行方式運行的方法。
答案
Python並不支持真正意義上的多線程。Python中提供了多線程包,可是若是你想經過多線程提升代碼的速度,使用多線程包並非個好主意。Python中有一個被稱爲Global Interpreter Lock(GIL)的東西,它會確保任什麼時候候你的多個線程中,只有一個被執行。線程的執行速度很是之快,會讓你誤覺得線程是並行執行的,可是實際上都是輪流執行。通過GIL這一道關卡處理,會增長執行的開銷。這意味着,若是你想提升代碼的運行速度,使用threading包並非一個很好的方法。
不過仍是有不少理由促使咱們使用threading包的。若是你想同時執行一些任務,並且不考慮效率問題,那麼使用這個包是徹底沒問題的,並且也很方便。可是大部分狀況下,並非這麼一回事,你會但願把多線程的部分外包給操做系統完成(經過開啓多個進程),或者是某些調用你的Python代碼的外部程序(例如Spark或Hadoop),又或者是你的Python代碼調用的其餘代碼(例如,你能夠在Python中調用C函數,用於處理開銷較大的多線程工做)。
爲何提這個問題
由於GIL就是個混帳東西(A-hole)。不少人花費大量的時間,試圖尋找本身多線程代碼中的瓶頸,直到他們明白GIL的存在。

47 將下面的函數按照執行效率高低排序。
它們都接受由0至1之間的數字構成的列表做爲輸入。這個列表能夠很長。一個輸入列表的示例以下:[random.random() for i in range(100000)]。你如何證實本身的答案是正確的。
def f1(lIn):
l1 = sorted(lIn)
l2 = [i for i in l1 if i<0.5]
return [i*i for i in l2]

def f2(lIn):
l1 = [i for i in lIn if i<0.5]
l2 = sorted(l1)
return [i*i for i in l2]

def f3(lIn):
l1 = [i*i for i in lIn]
l2 = sorted(l1)
return [i for i in l1 if i<(0.5*0.5)]

答案
按執行效率從高到低排列:f二、f1和f3。要證實這個答案是對的,你應該知道如何分析本身代碼的性能。Python中有一個很好的程序分析包,能夠知足這個需求。
import cProfile
lIn = [random.random() for i in range(100000)]
cProfile.run('f1(lIn)')
cProfile.run('f2(lIn)')
cProfile.run('f3(lIn)')

爲了向你們進行完整地說明,下面咱們給出上述分析代碼的輸出結果:

cProfile.run('f1(lIn)')
4 function calls in 0.045 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.009 0.009 0.044 0.044 :1(f1)
1 0.001 0.001 0.045 0.045 :1( )
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.035 0.035 0.035 0.035 {sorted}

cProfile.run('f2(lIn)')
4 function calls in 0.024 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.008 0.008 0.023 0.023 :1(f2)
1 0.001 0.001 0.024 0.024 :1( )
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.016 0.016 0.016 0.016 {sorted}

cProfile.run('f3(lIn)')
4 function calls in 0.055 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.016 0.016 0.054 0.054 :1(f3)
1 0.001 0.001 0.055 0.055 :1( )
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.038 0.038 0.038 0.038 {sorted}

爲何提這個問題?
定位並避免代碼瓶頸是很是有價值的技能。想要編寫許多高效的代碼,最終都要回答常識上來——在上面的例子中,若是列表較小的話,很明顯是先進行排序更快,所以若是你能夠在排序前先進行篩選,那一般都是比較好的作法。其餘不顯而易見的問題仍然能夠經過恰當的工具來定位。所以瞭解這些工具是有好處的。

48.如何用Python來進行查詢和替換一個文本字符串?
能夠使用sub()方法來進行查詢和替換,sub方法的格式爲:sub(replacement, string[, count=0])
replacement是被替換成的文本
string是須要被替換的文本
count是一個可選參數,指最大被替換的數量

49.Python裏面search()和match()的區別?
match()函數只檢測RE是否是在string的開始位置匹配,search()會掃描整個string查找匹配, 也就是說match()只有在0位置匹配成功的話纔有返回,若是不是開始位置匹配成功的話,match()就返回none

50.用Python匹配HTML tag的時候,<.>和<.?>有什麼區別?
前者是貪婪匹配,會從頭至尾匹配 xyz,然後者是非貪婪匹配,只匹配到第一個 >。

51.Python裏面如何生成隨機數?
import random
random.random()
它會返回一個隨機的0和1之間的浮點數

操做系統
1 select,poll和epoll
其實全部的I/O都是輪詢的方法,只不過實現的層面不一樣罷了.
這個問題可能有點深刻了,但相信能回答出這個問題是對I/O多路複用有很好的瞭解了.其中tornado使用的就是epoll的.
基本上select有3個缺點:
1.鏈接數受限
2.查找配對速度慢
3.數據由內核拷貝到用戶態
poll改善了第一個缺點
epoll改了三個缺點.
2 調度算法
1.先來先服務(FCFS, First Come First Serve)
2.短做業優先(SJF, Shortest Job First)
3.最高優先權調度(Priority Scheduling)
4.時間片輪轉(RR, Round Robin)
5.多級反饋隊列調度(multilevel feedback queue scheduling)
實時調度算法:
1.最先截至時間優先 EDF
2.最低鬆弛度優先 LLF
3 死鎖
緣由:
1.競爭資源
2.程序推動順序不當
必要條件:
1.互斥條件
2.請求和保持條件
3.不剝奪條件
4.環路等待條件
處理死鎖基本方法:
1.預防死鎖(摒棄除1之外的條件)
2.避免死鎖(銀行家算法)
3.檢測死鎖(資源分配圖)
4.解除死鎖
1.剝奪資源
2.撤銷進程
4 程序編譯與連接
Bulid過程能夠分解爲4個步驟:預處理(Prepressing), 編譯(Compilation)、彙編(Assembly)、連接(Linking)
以c語言爲例:
1 預處理
預編譯過程主要處理那些源文件中的以「#」開始的預編譯指令,主要處理規則有:
1.將全部的「#define」刪除,並展開所用的宏定義
2.處理全部條件預編譯指令,好比「#if」、「#ifdef」、 「#elif」、「#endif」
3.處理「#include」預編譯指令,將被包含的文件插入到該編譯指令的位置,注:此過程是遞歸進行的
4.刪除全部註釋
5.添加行號和文件名標識,以便於編譯時編譯器產生調試用的行號信息以及用於編譯時產生編譯錯誤或警告時可顯示行號
6.保留全部的#pragma編譯器指令。
2 編譯
編譯過程就是把預處理完的文件進行一系列的詞法分析、語法分析、語義分析及優化後生成相應的彙編代碼文件。這個過程是整個程序構建的核心部分。
3 彙編
彙編器是將彙編代碼轉化成機器能夠執行的指令,每一條彙編語句幾乎都是一條機器指令。通過編譯、連接、彙編輸出的文件成爲目標文件(Object File)
4 連接
連接的主要內容就是把各個模塊之間相互引用的部分處理好,使各個模塊能夠正確的拼接。
連接的主要過程包塊 地址和空間的分配(Address and Storage Allocation)、符號決議(Symbol Resolution)和重定位(Relocation)等步驟。
5 靜態連接和動態連接
靜態連接方法:靜態連接的時候,載入代碼就會把程序會用到的動態代碼或動態代碼的地址肯定下來
靜態庫的連接能夠使用靜態連接,動態連接庫也能夠使用這種方法連接導入庫
動態連接方法:使用這種方式的程序並不在一開始就完成動態連接,而是直到真正調用動態庫代碼時,載入程序才計算(被調用的那部分)動態代碼的邏輯地址,而後等到某個時候,程序又須要調用另外某塊動態代碼時,載入程序又去計算這部分代碼的邏輯地址,因此,這種方式使程序初始化時間較短,但運行期間的性能比不上靜態連接的程序
6 虛擬內存技術
虛擬存儲器是值具備請求調入功能和置換功能,能從邏輯上對內存容量加以擴充的一種存儲系統.
7 分頁和分段
分頁: 用戶程序的地址空間被劃分紅若干固定大小的區域,稱爲「頁」,相應地,內存空間分紅若干個物理塊,頁和塊的大小相等。可將用戶程序的任一頁放在內存的任一塊中,實現了離散分配。
分段: 將用戶程序地址空間分紅若干個大小不等的段,每段能夠定義一組相對完整的邏輯信息。存儲分配時,以段爲單位,段與段在內存中能夠不相鄰接,也實現了離散分配。
分頁與分段的主要區別
1.頁是信息的物理單位,分頁是爲了實現非連續分配,以便解決內存碎片問題,或者說分頁是因爲系統管理的須要.段是信息的邏輯單位,它含有一組意義相對完整的信息,分段的目的是爲了更好地實現共享,知足用戶的須要.
2.頁的大小固定,由系統肯定,將邏輯地址劃分爲頁號和頁內地址是由機器硬件實現的.而段的長度卻不固定,決定於用戶所編寫的程序,一般由編譯程序在對源程序進行編譯時根據信息的性質來劃分.
3.分頁的做業地址空間是一維的.分段的地址空間是二維的.
8 頁面置換算法
1.最佳置換算法OPT:不可能實現
2.先進先出FIFO
3.最近最久未使用算法LRU:最近一段時間裏最久沒有使用過的頁面予以置換.
4.clock算法
9 邊沿觸發和水平觸發
邊緣觸發是指每當狀態變化時發生一個 io 事件,條件觸發是隻要知足條件就發生一個 io 事件
數據庫
1 事務
數據庫事務(Database Transaction) ,是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。
2 數據庫索引
索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。
索引分爲聚簇索引和非聚簇索引兩種,聚簇索引 是按照數據存放的物理位置爲順序的,而非聚簇索引就不同了;聚簇索引能提升多行檢索的速度,而非聚簇索引對於單行的檢索很快。
推薦: http://tech.meituan.com/mysql-index.html
3 Redis原理

4 樂觀鎖和悲觀鎖
悲觀鎖:假定會發生併發衝突,屏蔽一切可能違反數據完整性的操做
樂觀鎖:假設不會發生併發衝突,只在提交操做時檢查是否違反數據完整性。
5 MVCC
大多數的MySQL事務型存儲引擎,如InnoDB,Falcon以及PBXT都不使用一種簡單的行鎖機制。事實上,他們都和另一種用來增長併發性的被稱爲「多版本併發控制(MVCC)」的機制來一塊兒使用。MVCC不僅使用在MySQL中,Oracle、PostgreSQL,以及其餘一些數據庫系統也一樣使用它。
6 MyISAM和InnoDB
MyISAM 適合於一些須要大量查詢的應用,但其對於有大量寫操做並非很好。甚至你只是須要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都沒法操做直到讀操做完成。另外,MyISAM 對於 SELECT COUNT(*) 這類的計算是超快無比的。
InnoDB 的趨勢會是一個很是複雜的存儲引擎,對於一些小的應用,它會比 MyISAM 還慢。他是它支持「行鎖」 ,因而在寫操做比較多的時候,會更優秀。而且,他還支持更多的高級應用,好比:事務。

網絡
1 三次握手
1.客戶端經過向服務器端發送一個SYN來建立一個主動打開,做爲三路握手的一部分。客戶端把這段鏈接的序號設定爲隨機數 A。
2.服務器端應當爲一個合法的SYN回送一個SYN/ACK。ACK 的確認碼應爲 A+1,SYN/ACK 包自己又有一個隨機序號 B。
3.最後,客戶端再發送一個ACK。當服務端受到這個ACK的時候,就完成了三路握手,並進入了鏈接建立狀態。此時包序號被設定爲收到的確認號 A+1,而響應則爲 B+1。
2 四次揮手
CP的鏈接的拆除須要發送四個包,所以稱爲四次揮手(four-way handshake)。客戶端或服務器都可主動發起揮手動做,在socket編程中,任何一方執行close()操做便可產生揮手操做。
(1)客戶端A發送一個FIN,用來關閉客戶A到服務器B的數據傳送。
(2)服務器B收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。和SYN同樣,一個FIN將佔用一個序號。
(3)服務器B關閉與客戶端A的鏈接,發送一個FIN給客戶端A。
(4)客戶端A發回ACK報文確認,並將確認序號設置爲收到序號加1。
3 ARP協議
地址解析協議(Address Resolution Protocol): 根據IP地址獲取物理地址的一個TCP/IP協議
4 urllib和urllib2的區別
這個面試官確實問過,當時答的urllib2能夠Post而urllib不能夠.
1.urllib提供urlencode方法用來GET查詢字符串的產生,而urllib2沒有。這是爲什麼urllib常和urllib2一塊兒使用的緣由。
2.urllib2能夠接受一個Request類的實例來設置URL請求的headers,urllib僅能夠接受URL。這意味着,你不能夠假裝你的User Agent字符串等。
5 Post和Get區別
GET後退按鈕/刷新無害,POST數據會被從新提交(瀏覽器應該告知用戶數據會被從新提交)。
GET書籤可收藏,POST爲書籤不可收藏。
GET能被緩存,POST不能緩存 。
GET編碼類型application/x-www-form-url,POST編碼類型encodedapplication/x-www-form-urlencoded 或 multipart/form-data。爲二進制數據使用多重編碼。
GET歷史參數保留在瀏覽器歷史中。POST參數不會保存在瀏覽器歷史中。
GET對數據長度有限制,當發送數據時,GET 方法向 URL 添加數據;URL 的長度是受限制的(URL 的最大長度是 2048 個字符)。POST無限制。
GET只容許 ASCII 字符。POST沒有限制。也容許二進制數據。
與 POST 相比,GET 的安全性較差,由於所發送的數據是 URL 的一部分。在發送密碼或其餘敏感信息時毫不要使用 GET !POST 比 GET 更安全,由於參數不會被保存在瀏覽器歷史或 web 服務器日誌中。
GET的數據在 URL 中對全部人都是可見的。POST的數據不會顯示在 URL 中。

6 Cookie和Session
Cookie Session
儲存位置 客戶端 服務器端
目的 跟蹤會話,也能夠保存用戶偏好設置或者保存用戶名密碼等 跟蹤會話
安全性 不安全 安全
session技術是要使用到cookie的,之因此出現session技術,主要是爲了安全。
7 apache和nginx的區別
nginx 相對 apache 的優勢:
輕量級,一樣起web 服務,比apache 佔用更少的內存及資源
抗併發,nginx 處理請求是異步非阻塞的,支持更多的併發鏈接,而apache 則是阻塞型的,在高併發下nginx 能保持低資源低消耗高性能
配置簡潔
高度模塊化的設計,編寫模塊相對簡單
社區活躍
apache 相對nginx 的優勢:
rewrite ,比nginx 的rewrite 強大
模塊超多,基本想到的均可以找到
少bug ,nginx 的bug 相對較多
超穩定
8 網站用戶密碼保存
1.明文保存
2.明文hash後保存,如md5
3.MD5+Salt方式,這個salt能夠隨機
4.知乎使用了Bcrypy(好像)加密
9 HTTP和HTTPS
HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用於安全的HTTP數據傳輸。https:URL代表它使用了HTTP,但HTTPS存在不一樣於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。這個系統的最初研發由網景公司進行,提供了身份驗證與加密通信方法,如今它被普遍用於萬維網上安全敏感的通信,例如交易支付方面。
超文本傳輸協議 (HTTP-Hypertext transfer protocol) 是一種詳細規定了瀏覽器和萬維網服務器之間互相通訊的規則,經過因特網傳送萬維網文檔的數據傳送協議。
10 XSRF和XSS
CSRF(Cross-site request forgery)跨站請求僞造
XSS(Cross Site Scripting)跨站腳本攻擊
CSRF重點在請求,XSS重點在腳本
11 RESTful架構(SOAP,RPC)
推薦: http://www.ruanyifeng.com/blog/2011/09/restful.html
12 SOAP
SOAP(原爲Simple Object Access Protocol的首字母縮寫,即簡單對象訪問協議)是交換數據的一種協議規範,使用在計算機網絡Web服務(web service)中,交換帶結構信息。SOAP爲了簡化網頁服務器(Web Server)從XML數據庫中提取數據時,節省去格式化頁面時間,以及不一樣應用程序之間按照HTTP通訊協議,聽從XML格式執行資料互換,使其抽象於語言實現、平臺和硬件。
13 RPC
RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。
總結:服務提供的兩大流派.傳統意義以方法調用爲導向通稱RPC。爲了企業SOA,若干廠商聯合推出webservice,制定了wsdl接口定義,傳輸soap.當互聯網時代,臃腫SOA被簡化爲http+xml/json.可是簡化出現各類混亂。以資源爲導向,任何操做無非是對資源的增刪改查,因而統一的REST出現了.
進化的順序: RPC -> SOAP -> RESTful
14 CGI和WSGI
CGI是通用網關接口,是鏈接web服務器和應用程序的接口,用戶經過CGI來獲取動態數據或文件等。
CGI程序是一個獨立的程序,它能夠用幾乎全部語言來寫,包括perl,c,lua,python等等。
WSGI, Web Server Gateway Interface,是Python應用程序或框架和Web服務器之間的一種接口,WSGI的其中一個目的就是讓用戶能夠用統一的語言(Python)編寫先後端。
16 中間人攻擊
在GFW裏家常便飯的,呵呵.
中間人攻擊(Man-in-the-middle attack,一般縮寫爲MITM)是指攻擊者與通信的兩端分別建立獨立的聯繫,並交換其所收到的數據,使通信的兩端認爲他們正在經過一個私密的鏈接與對方直接對話,但事實上整個會話都被攻擊者徹底控制。
17 c10k問題
所謂c10k問題,指的是服務器同時支持成千上萬個客戶端的問題,也就是concurrent 10 000 connection(這也是c10k這個名字的由來)。

18 socket
Socket=Ip address+ TCP/UDP + port
19 瀏覽器緩存
推薦: http://web.jobbole.com/84367/
瀏覽器緩存機制,其實主要就是HTTP協議定義的緩存機制(如: Expires; Cache-control等)
Expires策略
Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存取數據,而無需再次請求。
Cache-control策略(重點關注)
Cache-Control與Expires的做用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據仍是從新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細緻,若是同時設置的話,其優先級高於Expires
20 HTTP1.0和HTTP1.1
推薦: http://blog.csdn.net/elifefly/article/details/3964766
1.請求頭Host字段,一個服務器多個網站
2.長連接
3.文件斷點續傳
4.身份認證,狀態管理,Cache緩存
21 Ajax
AJAX,Asynchronous JavaScript and XML(異步的 JavaScript 和 XML), 是與在不從新加載整個頁面的狀況下,與服務器交換數據並更新部分網頁的技術。

數據結構
1 紅黑樹
紅黑樹與AVL的比較:
AVL是嚴格平衡樹,所以在增長或者刪除節點的時候,根據不一樣狀況,旋轉的次數比紅黑樹要多;
紅黑是用非嚴格的平衡來換取增刪節點時候旋轉次數的下降;
因此簡單說,若是你的應用中,搜索的次數遠遠大於插入和刪除,那麼選擇AVL,若是搜索,插入刪除次數幾乎差很少,應該選擇RB。
1 臺階問題/斐波納挈
一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
1 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)
第三種方法
1
2
3
4
5 def fib(n):
    a, b = 0, 1
    for _ in xrange(n):
        a, b = b, a + b
    return b
2 變態臺階問題
一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級……它也能夠跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
1 fib = lambda n: n if n < 2 else 2 * fib(n - 1)

3 矩形覆蓋
咱們能夠用21的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個21的小矩形無重疊地覆蓋一個2n的大矩形,總共有多少種方法?
第2
n個矩形的覆蓋方法等於第2(n-1)加上第2(n-2)的方法。

1 f = lambda n: 1 if n < 2 else f(n - 1) + f(n - 2)

4 楊氏矩陣查找
在一個m行n列二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。

5 去除列表中的重複元素
用集合
1 list(set(l))
用字典
1
2
3 l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print l2
用字典並保持順序

1
2
3
4 l1 = ['b','c','d','b','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print l2

1
2
3 l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]
面試官提到的,先排序而後刪除.
6 鏈表成對調換
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
7 建立字典的方法
1 直接建立
1 dict = {'name':'earth', 'port':'80'}
2 工廠方法
1
2
3 items=[('name','earth'),('port','80')]
dict2=dict(items)
dict1=dict((['name','earth'],['port','80']))
3 fromkeys()方法
1
2
3
4 dict1={}.fromkeys(('x','y'),-1)
dict={'x':-1,'y':-1}
dict2={}.fromkeys(('x','y'))
dict2={'x':None, 'y':None}
8 合併兩個有序列表
知乎遠程面試要求編程
尾遞歸
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
9 交叉鏈表求交點
去哪兒的面試,沒作出來.
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
10 二分查找

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)
11 快排
1
2
3
4
5
6
7
8
9
10
11
12 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))
12 找零問題
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)
13 廣度遍歷和深度遍歷二叉樹
給定一個數組,構建二叉樹,而且按層次打印這個二叉樹
## 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)
17 前中後序遍歷
深度遍歷改變順序就OK了
18 求最大樹深
1
2
3
4 def maxDepth(root):
        if not root:
            return 0
        return max(maxDepth(root.left), maxDepth(root.right)) + 1
19 求兩棵樹是否相同

1
2
3
4
5
6
7 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 前序中序求後序
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 單鏈表逆置
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

Python Web相關

解釋一下 WSGI 和 FastCGI 的關係?
CGI全稱是「公共網關接口」(CommonGateway Interface),HTTP服務器與你的或其它機器上的程序進行「交談」的一種工具,其程序須運行在網絡服務器上。 CGI能夠用任何一種語言編寫,只要這種語言具備標準輸入、輸出和環境變量。如php,perl,tcl等。
 
FastCGI像是一個常駐(long-live)型的CGI,它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute模式)。它還支持分佈式的運算, 即 FastCGI 程序能夠在網站服務器之外的主機上執行而且接受來自其它網站服務器來的請求。
FastCGI是語言無關的、可伸縮架構的CGI開放擴展,其主要行爲是將CGI解釋器進程保持在內存中並所以得到較高的性能。衆所周知,CGI解釋器的反覆加載是CGI性能低下的主要緣由,若是CGI解釋器保持在內存中並接受FastCGI進程管理器調度,則能夠提供良好的性能、伸縮性、Fail- Over特性等等。
WSGI的全稱爲: PythonWeb Server Gateway Interface v1.0 (Python Web 服務器網關接口),
它是 Python 應用程序和 WEB 服務器之間的一種接口。
它的做用,相似於FCGI 或 FASTCGI 之類的協議的做用。
WSGI 的目標,是要創建一個簡單的廣泛適用的服務器與 WEB 框架之間的接口。
Flup就是使用 Python 語言對 WSGI 的一種實現,是能夠用於 Python 的應用開發中的一種工具或者說是一種庫。
Spawn-fcgi是一個小程序,這個程序的做用是管理fast-cgi進程,那麼管理wsgi進程也是沒有問題的,功能和php-fpm相似。
故,簡單地說,WSGI和FastCGI都是一種CGI,用於鏈接WEB服務器與應用程序,而WSGI專指Python應用程序。而flup是WSGI的一種實現,Spawn-fcgi是用於管理flup進程的一個工具,能夠啓動多個wsgi進程,並管理它們。
解釋一下 Django 和 Tornado 的關係、差異
Django源自一個在線新聞 Web站點,於 2005 年以開源的形式被釋放出來。
Django 框架的核心組件有:
用於建立模型的對象關係映射爲最終用戶設計的完美管理界面一流的 URL 設計設計者友好的模板語言緩存系統等等
它鼓勵快速開發,並遵循MVC設計。Django遵照 BSD版權,最新發行版本是Django
1.4,於2012年03月23日發佈.Django的主要目的是簡便、快速的開發數據庫驅動的網站。它強調代碼複用,多個組件能夠很方便的以「插件」形式服務於整個框架,Django有許多功能強大的第三方插件,你甚至能夠很方便的開發出本身的工具包。這使得Django具備很強的可擴展性。它還強調快速開發和DRY(Do Not RepeatYourself)原則。
Tornado是 FriendFeed使用的可擴展的非阻塞式 web 服務器及其相關工具的開源版本。這個 Web 框架看起來有些像 web.py 或者 Google 的 webapp,不過爲了能有效利用非阻塞式服務器環境,這個 Web 框架還包含了一些相關的有用工具和優化。
Tornado 和如今的主流 Web 服務器框架(包括大多數Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。得利於其 非阻塞的方式和對epoll的運用,Tornado 每秒能夠處理數以千計的鏈接,這意味着對於實時 Web服務來講,Tornado 是一個理想的 Web 框架。咱們開發這個 Web 服務器的主要目的就是爲了處理 FriendFeed 的實時功能 ——在 FriendFeed 的應用裏每個活動用戶都會保持着一個服務器鏈接。(關於如何擴容 服務器,以處理數以千計的客戶端的鏈接的問題。
解釋下django-debug-toolbar的使用
使用django開發站點時,能夠使用django-debug-toolbar來進行調試。在settings.py中添加’debug_toolbar.middleware.DebugToolbarMiddleware’到項目的MIDDLEWARE_CLASSES 內。
解釋下Django使用redis緩存服務器
爲了能在Django中使用redis,還須要安裝redis for Django的插件。而後在Django的settings中配置了。如今鏈接和配置都已經完成了,接下來是一個簡單的例子: 
from django.conf import settings
from django.core.cache import cache

read cache user id

def read_from_cache(self, user_name):
    key = 'user_id_of_'+user_name
    value = cache.get(key)
    if value == None:
        data = None
    else:
        data = json.loads(value)
    return data

write cache user id

def write_to_cache(self, user_name):
    key = 'user_id_of_'+user_name
    cache.set(key, json.dumps(user_name), settings.NEVER_REDIS_TIMEOUT)
 
如何進行Django單元測試
Django的單元測試使用python的unittest模塊,這個模塊使用基於類的方法來定義測試。類名爲django.test.TestCase,繼承於python的unittest.TestCase。

from django.test import TestCase

from myapp.models import Animal
 
class AnimalTestCase(TestCase):
    def setUp(self):
        Animal.objects.create(name="lion", sound="roar")
        Animal.objects.create(name="cat", sound="meow")
 
    def test_animals_can_speak(self):
        """Animals that can speak are correctly identified"""
        lion = Animal.objects.get(name="lion")
        cat = Animal.objects.get(name="cat")
        self.assertEqual(lion.speak(), 'The lion says "roar"')
        self.assertEqual(cat.speak(), 'The cat says "meow"')
執行目錄下全部的測試(全部的test.py文件):運行測試的時候,測試程序會在全部以test開頭的文件中查找全部的test cases(inittest.TestCase的子類),自動創建測試集而後運行測試。 
1 $ python manage.py test
 
執行animals項目下tests包裏的測試:
$ python manage.py testanimals.tests
 
執行animals項目裏的test測試:
1 $ python manage.py testanimals
 
單獨執行某個test case: 
1 $ python manage.py testanimals.tests.AnimalTestCase
 
單獨執行某個測試方法: 
1 $ python manage.py testanimals.tests.AnimalTestCase.test_animals_can_speak
 
爲測試文件提供路徑:
1 $ python manage.py testanimals/
 
通配測試文件名: 
1 $ python manage.py test--pattern="tests_
.py"
 
啓用warnings提醒:
1 $ python -Wall manage.py test
 
解釋下Http協議
HTTP是一個屬於應用層的面向對象的協議,因爲其簡捷、快速的方式,適用於分佈式超媒體信息系統。
HTTP協議的主要特色可歸納以下:
1.支持客戶/服務器模式。
2.簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法經常使用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯繫的類型不一樣。因爲HTTP協議簡單,使得HTTP服務器的程序規模小,於是通訊速度很快。
3.靈活:HTTP容許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。
4.無鏈接:無鏈接的含義是限制每次鏈接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接。採用這種方式能夠節省傳輸時間。
5.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺乏狀態意味着若是後續處理須要前面的信息,則它必須重傳,這樣可能致使每次鏈接傳送的數據量增大。另外一方面,在服務器不須要先前信息時它的應答就較快。
解釋下Http請求頭和常見響應狀態碼
Accept:指瀏覽器或其餘客戶能夠接愛的MIME文件格式。能夠根據它判斷並返回適當的文件格式。
Accept-Charset:指出瀏覽器能夠接受的字符編碼。英文瀏覽器的默認值是ISO-8859-1.
Accept-Language:指出瀏覽器能夠接受的語言種類,如en或en-us,指英語。
Accept-Encoding:指出瀏覽器能夠接受的編碼方式。編碼方式不一樣於文件格式,它是爲了壓縮文件並加速文件傳遞速度。瀏覽器在接收到Web響應以後先解碼,而後再檢查文件格式。
Cache-Control:設置關於請求被代理服務器存儲的相關選項。通常用不到。
Connection:用來告訴服務器是否能夠維持固定的HTTP鏈接。HTTP/1.1使用Keep-Alive爲默認值,這樣,當瀏覽器須要多個文件時(好比一個HTML文件和相關的圖形文件),不須要每次都創建鏈接。
Content-Type:用來表名request的內容類型。能夠用HttpServletRequest的getContentType()方法取得。
Cookie:瀏覽器用這個屬性向服務器發送Cookie。Cookie是在瀏覽器中寄存的小型數據體,它能夠記載和服務器相關的用戶信息,也能夠用來實現會話功能。
 
狀態代碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值:
1xx:指示信息–表示請求已接收,繼續處理
2xx:成功–表示請求已被成功接收、理解、接受
3xx:重定向–要完成請求必須進行更進一步的操做
4xx:客戶端錯誤–請求有語法錯誤或請求沒法實現
5xx:服務器端錯誤–服務器未能實現合法的請求
常見狀態代碼、狀態描述、說明:
200 OK     //客戶端請求成功
400 Bad Request  //客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized //請求未經受權,這個狀態代碼必須和WWW-Authenticate報頭域一塊兒使用
403 Forbidden  //服務器收到請求,可是拒絕提供服務
404 Not Found  //請求資源不存在,eg:輸入了錯誤的URL
500 Internal Server Error //服務器發生不可預期的錯誤
503 Server Unavailable  //服務器當前不能處理客戶端的請求,一段時間後可能恢復正常
eg:HTTP/1.1 200 OK (CRLF)

爬蟲
1、試列出至少三種目前流行的大型數據庫的名稱:________、_________、__________,其中您最熟悉的是__________,從__________年開始使用。
Oracle,Mysql,SQLServer Oracle根據本身狀況

2、有表List,並有字段A、B、C,類型都是整數。表中有以下幾條記錄:
A B C
2 7 9
5 6 4
3 11 9
如今對該表一次完成如下操做:
查詢出B和C列的值,要求按B列升序排列
寫出一條新的記錄,值爲{7,9,8}
查詢C列,要求消除重複的值,按降序排列
寫出完成完成以上操做的標準的SQL語句,而且寫出操做3的結果。
create table List(A int,B int,C int)
Select B,C from List order by B
Insert into List values(7,9,8)
Select distinct(C) from List order by desc;
984

3、請簡要說明視圖的做用
1.數據庫視圖隱藏了數據的複雜性。
2.數據庫視圖有利於控制用戶對錶中某些列的訪問。
3.數據庫視圖使用戶查詢變得簡單。

4、列舉您使用過的python網絡爬蟲所用到的網絡數據包(最熟悉的在前):
requests、urllib、urllib二、httplib2

5、列舉您使用過的python網絡爬蟲所用到的解析數據包(最熟悉的在前):
BeautifulSoup、pyquery、Xpath、lxml

6、列舉您使用過的python中的編碼方式(最熟悉的在前):
UTF-8,ASCII,gbk

7、python3.5語言中enumerate的意思是_______________________
對於一個可迭代的(iterable)/可遍歷的對象(如列表、字符串),enumerate將其組成一個索引序列,利用它能夠同時得到索引和值
enumerate多用於在for循環中獲得計數

8、99的八進制表示是_______________________
143
9、請舉出三種經常使用的排序算法
冒泡、選擇、快速
10、列出比較熟悉的爬蟲框架
Scrapy
11、用四、九、二、7四個數字,能夠使用+、-、和/,每一個數字使用一次,使表達式的結果爲24,表達式是_____________________________
(9+7-4)
2
12、對你最有影響的或是您認爲最有價值的軟件方面的幾本書是?
十3、您最熟悉的Unix環境是_____________.Unix下查詢環境變量的命令是________,查詢腳本定時任務的命令是____________________
1AIX,envcrontab
十4、寫出在網絡爬蟲爬取數據的過程當中,遇到的防爬蟲問題的解決方案
經過headers反爬蟲:解決策略,僞造headers
基於用戶行爲反爬蟲:動態變化去爬取數據,模擬普通用戶的行爲
基於動態頁面的反爬蟲:跟蹤服務器發送的ajax請求,模擬ajax請求
十5、閱讀如下Python程序
foriinrange(5,0,-1):
print(i)
請在下面寫出打印結果
54321
十6、在某系統中一個整數佔用兩個八位字節,使用Python按下面的要求編寫完整程序。
接收從標準輸入中依次輸入的五個數字,將其組合成爲一個整數,放入全局變量n中,隨後在標準輸出輸出這個整數。(ord(char)獲取字符ASCII值的函數)

人,從剛出生來到這個世界,便開始探索這個世界。累了就歇會,精神了就繼續探索,直至死亡。

相關文章
相關標籤/搜索