那些坑爹的python面試題


python基礎知識思維導圖

           MyProcessOn

Python基礎:

說說你眼中的python( 2 )

  1. 談談你對python和其他語言的區別

    1. python 中,變量是以內容為基准而不是像 c 中以變量名為基准;
    2. python 中,一個變量可以以多個名稱訪問;
    3. python 中,數字類型的值是不可變的;
    4. python 中,編譯器會有一個小整數池的概念
  2. 談談你了了解的python種類以及相關特點
    Python的種類:
      - Cpython:使用 C 解釋器來解釋擴展名:.pyc C解釋器 -> .pyc(字節碼) -> 機器碼 -> cpu 
      - Jpython:使用 Java 解釋器 java 字節碼->機器碼 -> cpu 
      - ironpython:使用C#解釋器 C# 字節碼 -> 機器碼 -> cpu
        PYPY:運行速度快,原理:解釋器->字節碼->編譯成機器碼->直接運行機器碼,用戶運行時直接使用機器碼,所以運行速度快。
  3. 字節碼和機器器碼的關系和區別?
    - 機器碼(machine code),學名機器語言指令,有時也被稱為原生碼(Native Code),是電腦的CPU可直接解讀的數據。
    - 通常意義上來理解的話,機器碼就是計算機可以直接執行,並且執行速度最快的代碼。
    - 字節碼是一種中間狀態(中間碼)的二進制代碼(文件)。需要直譯器轉譯后才能成為機器碼。
  4. 為什么要學python
    1. 編譯型語言:一次性,將全部的程序編譯成二進制文件,然后在運行。(c,c++ ,go)
        優點:運行速度快。
        缺點:開發效率低,不能跨平台。
    2. 解釋型語言:當你的程序運行時,一行一行的解釋,並運行。(python , PHP)
        優點:調試代碼很方便,開發效率高,並且可以跨平台。
        缺點:運行速度慢。
    3. 我對程序的定義是人可以讀懂,而機器剛好可以執行的一段代碼,注重於代碼的可讀性。
       而Python的定位是“優雅”、“明確”、“簡單”,用它編寫的程序簡單易懂,這與我當初的想法不謀而合
  5. pep8規范
    代碼編排
      - 縮進。4個空格的縮進
      - 每行最大長度79,換行可以使用反斜杠
      - 類和top-level函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方盡量不要再空行。
    文檔編排
      - 模塊內容的順序:按標准、三方和自己編寫順序依次排放,之間空一行
      - 不要在一句import中多個庫
    空格的使用
    注釋
    文檔描述
    
  6. 123
  7. 123

py2與py3

  1. Python2和Python3的區別
    1. 性能
      - Py3.x性能比Py2.5慢15%,但還有很大的提升空間。 
    2.編碼 
      - Py3.X源碼文件默認使用utf-8編碼
    3. 語法
      - 去除print語句
      - 關鍵詞加入as 和with,還有True,False,None 
      - 刪除了raw_input,用input代替
      - 新的metaclass語法
    4. 字符串和字節串 
      - 字符串只有str一種類型
    5.數據類型
      - 只有一種整型——int
      - 新增了bytes類型
    6.面向對象 
      - 容器類和迭代器類被ABCs化,所以cellections模塊里的類型比Py2.5多了很多
      - 迭代器的next()方法改名為__next__(),並增加內置函數next(),用以調用迭代器的__next__()方法
    
  2. range和xrange的區別
    兩者的區別是xrange返回的是一個可迭代的對象,range返回的則是一個列表. 同時效率更高,更快。
      - 原因是實現的時候使用了 yield(此為python2.x回答,python3已刪除xrange)
  3. Python3和Python2中 int 和 long 的區別
    
    int <= 32 位整數
    long > 32 位整數
  4. 文件操作時:xreadlines和readlines的區別
    
    xreadlines = 返回一個生成器對象,
    readlines =  遍歷文件所有行
    
  5. 123
  6. 123

進制轉換

  1. 二進制轉換成十進制:v = "0b1111011"
    
    print(int(v,2)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
    
  2. 十進制轉換成二進制:v = 18
    
    print(bin(v))
    
  3. 八進制轉換成十進制:v = "011"
    
    print(int(v,8)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
    
  4. 十進制轉換成八進制:v = 30
    
    print(oct(v))
    
  5. 十六進制轉換成十進制:v = "0x12"
    
    print(int(v,16)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
    
  6. 123

運算符 ( 8 )

  1. 各類運算符詳解
  2. 各類運算符優先級
    
    運算符	                        描述
    **	                        指數 (最高優先級)
    ~ + -	                        按位翻轉, 一元加號和減號 (最后兩個的方法名為 +@ 和 -@)
    * / % //	                乘,除,取模和取整除
    + -	                        加法減法
    >> <<                      右移,左移運算符
    &	                        位 'AND'
    ^ |	                        位運算符
    <= < > >=                   比較運算符
    <> == !=	                等於運算符
    = %= /= //= -= += *= **=	賦值運算符
    is is not	                身份運算符
    in not in	                成員運算符
    and or not	                邏輯運算符
    
  3. 求結果:2 & 5
    按位與運算符:參與運算的兩個值,如果兩個相應位都為1,則該位的結果為1,否則為0
    Python結果:0
    
  4. 求結果:2 ^ 5
    按位異或運算符:當兩對應的二進位相異時,結果為1
    Python結果:7
  5. 求結果:1 or 3
    x or y
    布爾"或" :如果 x 是 True,它返回 x 的值,否則它返回 y 的計算值。
    Python結果:1
  6. 求結果:1 and 3
    x and y
    布爾"與" - :
    如果 x 為 False,x and y 返回 False,否則它返回 y 的計算值。
    python結果:>1
    
  7. 求結果:0 and 2 and 1
    Python結果: 0
  8. 求結果:0 and 2 or 1
    Python結果: 1
  9. 求結果:0 and 2 or 1 or 4
    Python結果:1
  10. 求結果:0 or False and 1
    Python結果:False
  11. 用⼀行代碼實現數值交換: a = 1 b = 2
    b,a = a,b
  12. 123

數據結構( 2 )

  1. 基本的數據類型和方法都有哪些
    列表:list
        - list.append(obj) # 在列表末尾添加新的對象
        - list.count(obj)  # 統計某個元素在列表中出現的次數
        - list.extend(seq) # 在列表末尾一次性追加另一個序列中的多個值(用新列表擴展原來的列表)
        - list.index(obj)  # 從列表中找出某個值第一個匹配項的索引位置
        - list.insert(index, obj)# 將對象插入列表
        - list.pop(obj=list[-1]) # 移除列表中的一個元素(默認最后一個元素),並且返回該元素的值
        - list.remove(obj) # 移除列表中某個值的第一個匹配項
        - list.reverse()   # 反向列表中元素
        - list.sort([func])# 對原列表進行排序
        - list.clear()     # 清空列表
        - list.copy()      # 復制列表
    字典:dict
        - popitem()    # 隨機返回並刪除字典中的一對鍵和值(一般刪除末尾對)。
        - key in dict  # 如果鍵在字典dict里返回true,否則返回false
        - radiansdict.copy()   # 返回一個字典的淺復制
        - radiansdict.keys()   # 以列表返回一個字典所有的鍵
        - radiansdict.items()  # 以列表返回可遍歷的(鍵, 值) 元組數組
        - radiansdict.clear()  # 刪除字典內所有元素
        - radiansdict.values() # 以列表返回字典中的所有值
        - radiansdict.fromkeys()    # 創建一個新字典,以序列seq中元素做字典的鍵,val為字典所有鍵對應的初始值
        - radiansdict.update(dict2) # 把字典dict2的鍵/值對更新到dict里
        - radiansdict.get(key, default=None)        # 返回指定鍵的值,如果值不在字典中返回default值
        - radiansdict.setdefault(key, default=None) # 和get()類似, 但如果鍵不存在於字典中,將會添加鍵並將值設為default
        - pop(key[,default])   # 刪除字典給定鍵 key 所對應的值,返回值為被刪除的值。key值必須給出。 否則,返回default值。
    字符串:str
        - upper()      # 轉換字符串中的小寫字母為大寫。
        - title()      # 返回"標題化"的字符串,就是說所有單詞都是以大寫開始,其余字母均為小寫(見 istitle())。
        - lower()      # 轉換字符串中所有大寫字符為小寫。
        - rstrip()     # 刪除字符串字符串末尾的空格.
        - lstrip()     # 截掉字符串左邊的空格或指定字符。
        - max(str)     # 返回字符串 str 中最大的字母。
        - min(str)     # 返回字符串 str 中最小的字母。
        - join(seq)    # 以指定字符串作為分隔符,將 seq 中所有的元素(的字符串表示)合並為一個新的字符串
         ...
        MySlef
    整數:int
        - bit_length()  # 查詢以二進制表示一個數字的值所需的位數
        - int.from_bytes(bytes,byteorder)  # 返回給定字節數組所表示的整數。
        - int.to_bytes(length,byteorder)   # 返回表示整數的字節數組。
    元組:tuple
        - len(tuple) # 計算元組元素個數。
        - max(tuple) # 返回元組中元素最大值。
        - min(tuple) # 返回元組中元素最小值。
        - tuple(seq) # 將列表轉換為元組。
    集合:set
        - set1 = set({1, 2, 'barry'}) # 創建集合
        - set2 = {1, 2, 'barry'}      # 創建集合
        - add  # 將元素添加到集合中。如果元素已經存在,這不起作用。
        - del set1  # 刪除集合- update # 迭代增加
        - clear  # 刪除此集合中的所有元素
        - remove # 刪除一個元素
        - pop    # 隨機刪除一個元素
        - issubset    # 子集
        - issuperset  # 超集
        - union  # 並集。(| 或者 union)
        - difference # 差集。(- 或者 difference)
        - intersection  # 交集。(&  或者 intersection)
        - isdisjoint    # 如果兩個集合有一個空交點,則返回True
        - intersection_update  # 用它自己和另一個交集更新一個集合。
        - difference_update  # 刪除另一個集合中本集合所擁有的所有元素
        - symmetric_difference  # 反交集。 (^ 或者 symmetric_difference)
    浮點:float
        - is_integer # 如果浮點數是整數,則返回True
    collections:Python內建的一個集合模塊,提供了許多有用的集合類。
        - Counter     # 是一個簡單的計數器,例如,統計字符出現的個數:
        - OrderedDict # 可以實現一個FIFO(先進先出)的dict,當容量超出限制時,先刪除最早添加的Key:
        - deque       # 是為了高效實現插入和刪除操作的雙向列表,適合用於隊列和棧:
        - defaultdict # 使用dict時,如果引用的Key不存在,就會拋出KeyError。如果希望key不存在時,返回一個默認值,就可以用defaultdict:
    
  2. 可變與不可變類型

    可變:
      - list,  - dict 
    不可變:
      -str,  - int,  - tuple,  - float, 
    
  3. 常⽤字符串格式化有哪些?
    
    1.占位符%
    %d 表示那個位置是整數;%f 表示浮點數;%s 表示字符串
      - print('Hello,%s' % 'Python')
      - print('Hello,%d%s%.2f' % (666, 'Python', 9.99)) # 打印:Hello,666Python10.00
    2.format
      - print('{k} is {v}'.format(k='python', v='easy'))  # 通過關鍵字
      - print('{0} is {1}'.format('python', 'easy'))      # 通過關鍵字
    
  4. 常用字符串格式化有哪些?
    
    - 0
    - ""
    - []
    - {}
    - (,)
    - None
    
  5. *Python2和Python3有差嗎
    
    Python2和Python3有差嗎
    
  6. Python2和Python3有差嗎
    
    is和==的區別
    
  7. 123
  8. 123
  9. 123
  10. 123
  11. 123
  12. 123

函數( 9 )

  1. 函數參數傳遞的是什么? 引用、內存地址
    # 默認參數盡量避免使用可變數據類型
    # 默認參數只會被執行一次:第一次調用函數時,默認參數被初始化為【】,以后每次調用時都會使用已經初始化的【】。
    >>> def func(a,a1 = []):  #默認參數
    ...     a1.append(a)
    ...     print(a1)
    
    >>> func()
    [1]
    >>> func()
    [1, 1]
    >>> func()
    [1, 1, 1]
    >>> func()
    [1, 1, 1, 1]
  2. 閉包函數
    def foo():
        m, n=3, 5
        def bar():
            a=4
            return m+n+a
        return bar
    >>>bar =  foo()
    >>>bar()
    12
    
    說明:
    bar在foo函數的代碼塊中定義。我們稱bar是foo的內部函數。
    在bar的局部作用域中可以直接訪問foo局部作用域中定義的m、n變量。 簡單的說,這種內部函數可以使用外部函數變量的行為,就叫閉包。 - 閉包的意義與應用: 延遲計算; - 閉包的意義: 返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域 #應用領域:延遲計算(原來我們是傳參,現在我們是包起來) 裝飾器就是閉包函數的一種應用場景
  3. 談談你對閉包的理解?
    
    說明:
    bar在foo函數的代碼塊中定義。我們稱bar是foo的內部函數。
    
    在bar的局部作用域中可以直接訪問foo局部作用域中定義的m、n變量。
    簡單的說,這種內部函數可以使用外部函數變量的行為,就叫閉包。
    
    閉包的意義與應用:
    # 裝飾器就是閉包函數的一種應用場景
    # 閉包的意義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域
    # 應用領域:延遲計算(原來我們是傳參,現在我們是包起來)
        from urllib.request import urlopen
        def index(url):
            def get():
                return urlopen(url).read()
            return get
    
        baidu=index('http://www.baidu.com')
        print(baidu().decode('utf-8'))
    
  4. 必會內置函數 - map
    介紹:
        會根據提供的函數對指定序列做映射。
        第一個參數 function 以參數序列中的每一個元素調用 function 函數,返回包含每次 function 函數返回值的新列表。
    語法:
        map(function, iterable, ...)
          - function --  函數,有兩個參數
          - iterable  --  一個或多個序列
    應用示例:
    >>>def square(x) :            # 計算平方數
    ...     return x ** 2
    ... 
    >>> map(square, [1,2,3,4,5])   # 計算列表各個元素的平方
    [1, 4, 9, 16, 25]
    >>> map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函數
    [1, 4, 9, 16, 25]
     
    # 提供了兩個列表,對相同位置的列表數據進行相加
    >>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
    [3, 7, 11, 15, 19]
  5. 必會內置函數 - filter
    介紹:
        函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。
        該接收兩個參數,第一個為函數,第二個為序列,序列的每個元素作為參數傳遞給函數進行判,然后返回 True 或 False,最后將返回 True 的元素放到新列表中。
    語法:
        filter(function, iterable)
          - function -- 判斷函數。
          - iterable -- 可迭代對象。
    應用示例1:過濾出列表中的所有奇數:
        def is_odd(n):
            return n % 2 == 1
        newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            print(newlist)
        >>>[1, 3, 5, 7, 9]
    應用示例2:過濾出1~100中平方根是整數的數
        import math
        def is_sqr(x):
            return math.sqrt(x) % 1 == 0
        newlist = filter(is_sqr, range(1, 101))
        print(newlist)
        >>>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    應用示例3:filter相較於py2的區別
        python2中返回的是過濾后的列表, 而python3中返回到是一個filter類
        filter類實現了__iter__和__next__方法, 可以看成是一個迭代器, 有惰性運算的特性, 相對python2提升了性能, 可以節約內存。
        a = filter(lambda x: x % 2 == 0, range(10))
        print(a)
        >>><filter object at 0x000001CC57668518>
    
  6. 必會內置函數 - zip
    介紹:
        函數用於將可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表。
    如果各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同,利用 * 號操作符,可以將元組解壓為列表。
    語法:
        zip([iterable, ...])
          - iterabl -- 一個或多個迭代器;
    返回值:
        - 返回元組列表。
    應用示例:
        >>>a = [1,2,3]
        >>> b = [4,5,6]
        >>> c = [4,5,6,7,8]
        >>> zipped = zip(a,b)     # 打包為元組的列表
        [(1, 4), (2, 5), (3, 6)]
        >>> zip(a,c)              # 元素個數與最短的列表一致
        [(1, 4), (2, 5), (3, 6)]
        >>> zip(*zipped)          # 與 zip 相反,可理解為解壓,返回二維矩陣式
        [(1, 2, 3), (4, 5, 6)]
  7. 必會內置函數 - isinstance
    介紹:
        函數來判斷一個對象是否是一個已知的類型,類似 type()。
    語法:
        isinstance(object, classinfo)
          - object -- 實例對象。
          - classinfo -- 可以是直接或間接類名、基本類型或者由它們組成的元組。
    返回值:
        如果對象的類型與參數二的類型(classinfo)相同則返回 True,否則返回 False。。
    應用示例:
        >>>a = 2
        >>> isinstance (a,int)
        True
        >>> isinstance (a,str)
        False
        >>> isinstance (a,(str,int,list))    # 是元組中的一個返回 True
        True
    
  8. isinstance() 與 type()的區別
    介紹
    1. type() 不會認為子類是一種父類類型,不考慮繼承關系。
    2. isinstance() 會認為子類是一種父類類型,考慮繼承關系。
    # 如果要判斷兩個類型是否相同推薦使用 isinstance()。
    示例:
        class A:
            pass
        class B(A):
            pass
    
        isinstance(A(), A)    # returns True
        type(A()) == A        # returns True
        isinstance(B(), A)    # returns True
        type(B()) == A        # returns False
    
  9. pass的作用
     - 1. 不做任何事情,一般用做占位語句。
     - 2. pass是空語句,是為了保持程序結構的完整性。
    
  10. *args和**kwarg的作用
    位置參數(positional argument) 
    關鍵詞參數(keyword argument)
      - *args表示任何多個無名參數,它本質是一個 tuple ; 
      - **kwargs表示關鍵字參數,它本質上是一個 dict ;
      - 並且同時使用*args和**kwargs時,必須*args參數列要在**kwargs前。
    
  11. is和==的區別
    
      - is 比較的是兩個實例對象是不是完全相同,它們是不是同一個對象,占用的內存地址是否相同。萊布尼茨說過:“世界上沒有兩片完全相同的葉子”,這個is正是這樣的比較,
    比較是不是同一片葉子(即比較的id是否相同,這id類似於人的身份證標識)。 - == 比較的是兩個對象的內容是否相等,即內存地址可以不一樣,內容一樣就可以了。這里比較的並非是同一片葉子,可能葉子的種類或者脈絡相同就可以了。 默認會調用對象的 __eq__()方法。
  12. 123
  13. 123
  14. 123

函數的應用

  1. ⼀⾏代碼實現9*9乘法表
    print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))
    
  2. 如何實現 “1,2,3” 變成 [‘1’,’2’,’3’]
    
     - list("1,2,3".split(','))
    
  3. 如何實現[‘1’,’2’,’3’]變成[1,2,3]
    
    [int(x) for x in ['1','2','3']]
    
  4. 如何⽤⼀⾏代碼⽣成[1,4,9,16,25,36,49,64,81,100]
    
    [i*i for i in range(1,11)]
    
  5. ⼀行代碼實現刪除列表中重復的值
    
    list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))
    
  6. 請編寫一個函數實現將IP地址轉換成一個整數
    如 10.3.9.12 轉換規則為:
    10 00001010
    3   00000011
    9   00001001
    12 00001100
    再將以上二進制拼接起來計算十進制結果:00001010 00000011 00001001 00001100 = ?

    
    a = "10.3.9.12"
    def func(ip):
        Iplist = ip.split(".")  # ['10', '3', '9', '12']
        res = " "
        temp = []
        for i in Iplist:        # <class 'str'>
            i = int(i)          # <class 'int'>
            i = bin(i)[2:]      # <class 'str'>
            temp.append(i.rjust(8, "0"))   # 右對齊,向左填充數據
        res = res.join(temp)
        return res
    
    # 一行代碼實現:
    b = "".join([" ".join(str(bin(int(i))[2:]).rjust(8,"0") for i in a.split("."))])
    print(func(a))
    
    - "00001010 00000011 00001001 00001100"
    
  7. 用Python實現⼀個⼆分查找的函數 二分查找算法:
            簡單的說,就是將一個列表先排序好,比如按照從小到大的順序排列好,當給定一個數據,比如3,查找3在列表中的位置時,可以先找到列表中間的數li[middle]和3進行比較,當它比3小時,那么3一定是在列表的右邊,反之,則3在列表的左邊,比如它比3小,則下次就可以只比較[middle+1, end]的數,繼續使用二分法,將它一分為二,直到找到3這個數返回或者列表全部遍歷完成(3不在列表中)
            優點:效率高,時間復雜度為O(logN);
            缺點:數據要是有序的,順序存儲。
    
    li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     
    def search(someone, li):
        l = -1
        h = len(li)
     
        while l + 1 != h:
            m = int((l + h) / 2)
            if li[m] < someone:
                l = m
            else:
                h = m
        p = h
        if p >= len(li) or li[p] != someone:
            print("元素不存在")
        else:
            str = "元素索引為%d" % p
            print(str)
     
    search(3, li)  # 元素索引為2
    
  8. 1
  9. 1
  10. 1
  11. 1
  12. 1
  13. 1
  14. 請⽤代碼簡答實現stack
    
    1. Stack() 創建一個新的空棧
    2. push(item) 添加一個新的元素item到棧頂
    3. pop() 彈出棧頂元素
    4. peek() 返回棧頂元素
    5. is_empty() 判斷棧是否為空
    6. size() 返回棧的元素個數
    
    class Stack(object):
        """棧"""
        def __init__(self):
             self.items = []
     
        def is_empty(self):
            """判斷是否為空"""
            return self.items == []
     
        def push(self, item):
            """加入元素"""
            self.items.append(item)
     
        def pop(self):
            """彈出元素"""
            return self.items.pop()
     
        def peek(self):
            """返回棧頂元素"""
            return self.items[len(self.items)-1]
     
        def size(self):
            """返回棧的大小"""
            return len(self.items)
     
    if __name__ == "__main__":
        stack = Stack()
        stack.push("hello")
        stack.push("world")
        stack.push("lcg")
        print stack.size()
        print stack.peek()
        print stack.pop()
        print stack.pop()
        print stack.pop()
    
  15. 內置函數:map、reduce、filter的用法和區別
    
    map:遍歷序列,對序列中每個元素進行操作,最終獲取新的序列。
      - 每個元素增加100:
        - li = [11, 22, 33]
        - new_list = map(lambda a: a + 100, li)
      - 兩個列表對應元素相加
        - li = [11, 22, 33]
        - sl = [1, 2, 3, 4]
        - new_list = map(lambda a, b: a + b, li, sl)
    
    filter:對於序列中的元素進行篩選,最終獲取符合條件的序列。
      - 獲取列表中大於12的所有元素集合
        - li = [11, 22, 33]
        - new_list = filter(lambda arg: arg > 22, li)
        - # filter第一個參數為空,將獲取原來序列
    
    reduce:對於序列內所有元素進行累計操作。
      - 獲取序列所有元素的和
        - li = [11, 22, 33]
        - result = reduce(lambda arg1, arg2: arg1 + arg2, li)
      - # reduce的第一個參數,函數必須要有兩個參數
      - # reduce的第二個參數,要循環的序列
      - # reduce的第三個參數,初始值
    

函數的騷操作( 8 )

  1. 手寫:三元運算符
    >>> val = "aaa" if 1==1 else "bbb"
    >>> val
    'aaa'
    >>>
  2. 手寫:lambda表達式
    my_lambda = lambda arg : arg + 1
  3. 手寫:列表推導式
    def func(x):
        return x+1
    
    variable = [ func  for num in range(10) if num == 2]
      func:        # 列表生成元素表達式,可以是有返回值的函數或者 lambda 函數。
      for num in range(10):  # 迭代 range(10) 將 num 傳入 func 表達式中。
      if num == 2: # 根據條件過濾哪些值可以。
  4. 手寫:列表推導式 + lambda表達式 :# 一行代碼寫出30以內所有能被3整除的數的平方:
    
    # 錯誤示例:不能使用列表生成式
        a = [lambda :i*i for i in range(31) if i%3 is 0]
    # 錯誤調用方式: # 每次只會返回最后一個被循環的range(30)!
        >>>a
        [. at 0x000002C97... ,>> a[0]
        . at 0x000002C977B96BF8>
        >>> a[0]()
        900
    # 正確示例:使用生成器迭代執行   # 注意括號!
        a = (lambda :i*i for i in range(31) if i%3 is 0) 
    # 調用方式:
    >>> a.__iter__
    <method-wrapper '__iter__' of generator object at 0x000002C977AF5938>
    >>> a.__iter__()
     at 0x000002C977AF5938>
    >>> a.__iter__().__next__
    <method-wrapper '__next__' of generator object at 0x000002C977AF5938>
    >>> a.__iter__().__next__()
    . at 0x000002C977B8CF28>
    >>> a.__iter__().__next__()()
    9
  5. 手寫字典推導式
    # 推導式示例:
    >>> mcase = {'a': 10, 'b': 34}
    >>> mcase_frequency = {mcase[k]: k for k in mcase}
    >>> print(mcase_frequency)
    {10: 'a', 34: 'b'}
  6. 手寫:字典推導式:合並大小寫對應的value值,將k統一成小寫
    #   _._
    >>> mcase = {'a': 10, b': 34, 'A': 7, 'Z': 3}
    >>> mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
    >>> print(mcase_frequency)
    {'a': 17, 'b': 34, 'z': 3}
  7. 手寫:集合推導式
    # 集合推導式示例
    >>> squared = {x**2 for x in [ i for i in range(-5,10) ]}
    >>> print(squared)
    {1, 4}
  8. 列表推導式list comprehension和生成器的優劣

    1. 列表推導式是將所有的值一次性加載到內存中
    2. 生成器是將列表推導式的[]改成(),不會將所有的值一次性加載到內存中,延遲計算,一次返回一個結果,
       它不會一次生成所有的結果,這對大數據量處理,非常有用
    # 生成器函數: 一個函數中包含了yield關鍵詞,那么這個函數就不是普通的函數,是一個生成器函數
    # 調用生成器函數,不會立馬執行該函數里面的代碼, 而是會返回一個 生成器對象

python三神器( 7 )

  1. 生成器、迭代器、裝飾器、可迭代對象的區別
    容器:
       - 是一系列元素的集合,str、list、set、dict、file、sockets對象都可以看作是容器,容器都可以被迭代(用在for,while等語句中),因此他們被稱為可迭代對象。
    可迭代對象實現了__iter__方法,該方法返回一個迭代器對象。
    迭代器:
        - 持有一個內部狀態的字段,用於記錄下次迭代返回值,它實現了__next__和__iter__方法,迭代器不會一次性把所有元素加載到內存,而是需要的時候才生成返回結果。
    生成器:
        - 是一種特殊的迭代器,它的返回值不是通過return而是用yield。
    裝飾器
        - 在不改變原函數代碼的基礎上,在執行前后進行定制操作
    
  2. 生成器
    - 生成器,一個函數內部存在yield關鍵字;v = 函數()。
      應用場景:
        - range/xrange
        - py2: range(100000000),立即創建;xrange(100000000)生成器;
        - py3: range(100000000)生成器;
        - redis獲取值
    	conn = Redis(...)
    	def hscan_iter(self, name, match=None, count=None):
    	"""
    	Make an iterator using the HSCAN command so that the client doesn't
    	need to remember the cursor position.
            ``match`` allows for filtering the keys by pattern
            ``count`` allows for hint the minimum number of returns
    	"""
            cursor = '0'
            while cursor != 0:
                # 去redis中獲取數據:12
                # cursor,下一次取的位置
                # data:本地獲取的12條數數據
                cursor, data = self.hscan(name, cursor=cursor, match=match, count=count)
                for item in data.items():
                    yield item
    
  3. 迭代器
    - 迭代器,內部實現__next__方法,幫助我們向后一個一個取值。
    
  4. 可迭代對象
    可迭代對象介紹
      - 一個類內部實現 __iter__ 方法且返回一個迭代器
          - 實例:
            class Foo(object):
                def __iter__(self):
                    return iter([11,22,33,44])
            obj = Foo()
      - 應用場景:
          - wtform中對form對象進行循環時,顯示form中包含的所有字段。
          - 列表、字典、元組
    
  5. 什么是裝飾器
    裝飾器介紹
      - 在不改變原函數代碼的基礎上,在執行前后進行定制操作
      - 手寫
      - 應用場景:
        - Flask : 路由、before_request、after_request
        - Django: csrf、緩存、內置用戶登錄認證
        - functools:緩存、warper
    
  6. 手寫一個裝飾器
    def waper(func):
        def inner(*args, **kwargs):
            res = func(*args, **kwargs)
           return res
        return inner
  7. 帶參數的裝飾器
    def waper(func, x,y):
        print( int(x) + int(y) )
        @functools.wapper               # 保留原函數信息
        def inner(*args, **kwargs):
            """blabla的一些注釋"""
            res = func(*args, **kwargs)
           return res
        return inner
    
    @wapper(1,2)
    def func(a):
        return a
    func(123)

面向對象 ( 10 )

  1. 談談你對面向對象的認識
    - 簡單描述 :繼承、封裝、多態 
    - 系統描述 :先對代碼進行分類:按屬性進行划分(file,DB),按功能划分,將同一類方法分為一類。將方法中共同的參數封裝到對象中,把共用值封裝到對象中。
    面向對象的私有字段:
      - python中一切皆對象
      1. 封裝:對數據的,對對象的封裝。
      2. 繼承:在類的基礎上進行二次開發,通過函數super() 或者"基類名.方法名() "的方式實現這一目的的。
      3. 多態:同一個方法處於不同對象中,可以產生不同的結果
    - 多態示例
    # 鴨子模型
    class A:
    def send(self):
    pass
    class B:
    def send(self):
    pass
    def func(arg):
    arg.send()
    obj = B()
    func(obj)
  2. 你知道哪些雙下划線方法
    - 雙下划線:
      1. __getattr__:反射
         應用場景:
           - CBV
           - Django 配置文件
           - wtforms中的Form()實例化中 將"_fields中的數據封裝到Form類中"
      2. __mro__:定義解析類繼承的順序
         應用場景:wtforms中 FormMeta中繼承的優先級
      3. __dict__:用來存儲對象屬性的一個字典,其鍵為屬性名,值為屬性的值
         - __dict__ 與 dir()的區別:
           1. dir()是一個函數,返回值是list
           2. dir用來尋找一個對象的所有屬性值,包括__dict__中的屬性,__dict__是dir()的子集
      4. __new__ :
         - 當你繼承一些不可變的class時(比如int, str, tuple), 提供給你一個自定義這些類的實例化過程的途徑。
         - 實現自定義 metaclass 
         應用場景:
           - wtforms 字段實例化時返回:不是StringField,而是UNboundField
           - rest_framework:many=Ture 中的序列化
           - 單例模式
      5. __call__:作用是使實例能夠像函數一樣被調用,同時不影響實例本身的生命周期, (__call__()不影響一個實例的構造和析構)
                   但是__call__()可以用來改變實例的內部成員。
         __call__ 與 __init__的區別
         應用場景:
           - FLask 請求的入口app.run()
           - 字段生成標簽時:字段.__str__ ==> 字段.__call__ ==> 插件.__call__
      6. __iter__:
         迭代器為什么要一定實現__iter__方法(為什么要返回自身)
         應用場景:wtforms中BaseForm中循環所有字段時自定義了__iter__方法
  3. metaclass的作用
    - 作用:用於指定當前類事業那個類來創建 - 場景:在類創建之前定制的操作 示例:wtforms中對字段進行排序
  4. super的作用:

    子類繼承父類的方法,其繼承順序按照 __mro__來定義
  5. 新式類與經典類的區別
    新式類跟經典類的差別主要是以下幾點:
      1. 新式類對象可以直接通過__class__屬性獲取自身類型:type
      2. 繼承搜索的順序發生了改變,經典類多繼承屬性搜索順序 :
          - 先深入繼承樹左側,再返回,開始找右側;
          - 新式類多繼承屬性搜索順序: 先水平搜索,然后再向上移動。
            ps:(經典類深度優先,新式類廣度優先)
      3. 新式類增加了__slots__內置屬性, 可以把實例屬性的種類鎖定到__slots__規定的范圍之中。
      4. 新式類增加了__getattribute__方法
    
    Python 2.x中默認都是經典類,只有顯式繼承了object才是新式類
    Python 3.x中默認都是新式類,不必顯式的繼承object
  6. 深度優先和廣度優先是什么
    python的類可以繼承多個類,python的類如果繼承了多個類,那么其尋找的方法有兩種:
      - 當類是經典類時:多繼承情況下,會按照深度優先的方式查找
      - 當類是新式類時:多繼承情況下,會按照廣度優先的方式查找
    簡單點說就是:經典類是縱向查找,新式類是橫向查找
  7. 什么是函數什么是方法?
    from types import MethodType,FunctionType
    
    class func(object): def foo(self): print(1) Fun = func() print(type(func.foo)) >>> <class 'function'>
    print(type(Fun.foo)) >>> <class 'method'>
    print(isinstance(func.foo,FunctionType)) >>> True
    print(isinstance(Fun.foo,MethodType)) >>> True 通過類去調用函數foo時,不需要傳self參數。此時foo為函數 如果通過對象Fun去調用foo時,對象自動傳參self。而foo則是一個方法
  8. 手寫三個使用不同方法實現的單例模式

    單例模式:一個類只能有一個實例化對象
    應用場景:Django中的admin組件中admin.site()就是由單例模式創建的,其中封裝了所有的表對象

    1. 文件導入 :import方法
    # 作為python的模塊是天然的單例模式
    class My_Singleton(object):
        def foo(self):
            pass
    my_singleton = My_Singleton()
    # to use
    from mysingleton import my_singleton
    my_singleton.foo()
    
    
    2. 使用 __new__ 方法:
    --------------------------------(1. # 無法支持多線程 :)------------------------------
    class Singleton(object):
        def __init__(self,name):
            self.name = name
        def __new__(cls, *args, **kwargs):
            if not hasattr(Singleton, "instance"):
                Singleton.instance = object.__new__(cls)
            return Singleton.instance
    # to use :
    obj0 = Singleton("alex")
    obj1 = Singleton("alex")
    obj2 = Singleton("alex")
    
    ----------------------------------(2. # 支持多線程:)---------------------------------
    import threading
    class Singleton(object):
        instance_lock = threading.Lock() # 為線程加互斥鎖
        def __init__(self):
            pass
        def __new__(cls, *args, **kwargs):
            if not hasattr(Singleton, "instance"):
                with Singleton.instance_lock:
                    if not hasattr(Singleton, "instance"):
                        Singleton.instance = object.__new__(cls)
                    return Singleton.instance
            return Singleton.instance
    def task():
        obj = Singleton()
        print(obj)
    for i in range(5):
        t = threading.Thread(target=task)
        t.start()
    
    
    3. 使用類實現
    --------------------------------(1. # 無法支持多線程 :)------------------------------
    import threading
    class Singleton(object): 
        def __init__(self):
            pass
        @classmethod 
        def instance(cls, *args, **kwargs): 
            if not hasattr(Singleton, "_instance"): 
                Singleton._instance = Singleton(*args, **kwargs) 
        return Singleton._instance
    # to use
    obj = Singleton.instance()
    obj2 = Singleton.instance()
    print(id(obj), id(obj2))
    ----------------------------------(2. # 支持多線程:)---------------------------------
    import time
    import threading
    class Singleton(object):
        _instance_lock = threading.Lock()
        def __init__(self):
            time.sleep(1)
        @classmethod
        def instance(cls, *args, **kwargs):
            if not hasattr(Singleton, "_instance"):
                with Singleton._instance_lock:
                    if not hasattr(Singleton, "_instance"):
                        Singleton._instance = Singleton(*args, **kwargs)
            return Singleton._instance
    # 第一次調用
    def task(arg):
        obj = Singleton.instance()
        print(obj)
    for i in range(10):
        t = threading.Thread(target=task,args=[i,])
        t.start()
    # 第二次調用    
    time.sleep(20)
    obj = Singleton.instance()
    obj2 = Singleton.instance()
    print(id(obj, id(obj2)
    
    
    4. 基於metaclass
    --------------------------------------( 方法一 )--------------------------------------
    # 創建對象
    class SingletonType(type):
        def __call__(cls, *args, **kwargs):
            obj = super(SingletonType,cls).__call__(*args, **kwargs)   #type類幫創建__new__和__init__並返回
            return obj
    class Foo(metaclass=SingletonType):
        def __init__(self,name):
            self.name = name
    # to use
    obj = Foo("alex")
    print(id(obj1))
    --------------------------------------( 方法二 )--------------------------------------
    
    import threading
    class SingletonType(type):
        _instance_lock = threading.Lock()
        def __call__(cls, *args, **kwargs):
            if not hasattr(cls, "_instance"):
                with SingletonType._instance_lock:
                    if not hasattr(cls, "_instance"):
                        cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
            return cls._instance
    class Foo(metaclass=SingletonType):
        def __init__(self,name):
            self.name = name
    # to use
    obj1 = Foo('name')
    obj2 = Foo('name')
    print(id(obj1),id(obj2))
    
  9. __new__, __init__的區別

    1. __new__是一個靜態方法,而__init__是一個實例方法.
    2. __new__方法會返回一個創建的實例,而__init__什么都不返回.
    3. 只有在__new__返回一個cls的實例時后面的__init__才能被調用.
    4. 當創建一個新實例時調用__new__,初始化一個實例時用__init__.
    5. 繼承自object的新式類才有__new__
    6. __new__至少要有一個參數cls,代表當前類,此參數在實例化時由Python解釋器自動識別
    7. __new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,
      可以return父類(通過super(當前類名, cls))__new__出來的實例,或者直接是object的__new__出來的實例
    8. __init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
    9. 如果__new__創建的是當前類的實例,會自動調用__init__函數,通過return語句里面調用的__new__函數的第一個參數是cls來保證是當前類實例,
    10. 如果是其他類的類名,;那么實際創建返回的就是其他類的實例,其實就不會調用當前類的__init__函數,也不會調用其他類的__init__函數。

    new與init的關系:

        1. new優於init加載執行

        2. 只能通過重寫new方法來自定義不可變的類對象:(int,str,tuple),--->init方法不行

        3. 通過new方法可以實現單例模式

    lass Singleton(object):

        def __new__(cls):

            # 關鍵在於這,每一次實例化的時候,我們都只會返回這同一個instance對象

            if not hasattr(cls, 'instance'):

                cls.instance = super(Singleton, cls).__new__(cls)

            return cls.instance

    obj1 = Singleton()

    obj2 = Singleton()

    obj1.attr1 = 'value1'

    print obj1.attr1, obj2.attr1

    print obj1 is obj2

  10. 知道有哪些類的雙下划線方法,並說明作用,返回值? https://www.zybuluo.com/kingwhite/note/136247
  11. 面向對象中super的作用?
    用於執行子類繼承基類的方法
    
  12. 123
  13. 123
  14. 123

模塊 ( 26 )

  1. 你的常用模塊都有哪些 ( 1 )

    copy : 用於深淺拷貝
    os :與操作系統交互的一個接口 比如用來處理文件和目錄
    random :隨機模塊
    sys:負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境。
    json:序列化
    re : 正則模塊
    logging : 日志模塊
    requests: 爬取數據
    timeit :
    subprocess:與OS模塊相同,區別與異步提交命令不等待輸出。與OS模塊的區別

copy模塊 ( 1 )

  1. 淺拷貝與深拷貝的實現方式及區別,如果你來設計Deepcopy,如何實現
    淺拷貝:只拷貝父對象,不會拷貝對象的內部的子對象(父對象不同,子對象進行引用,ID相同)
    >>> a = [1,[1,3],3]
    >>> import copy
    >>> b = copy.copy(a)
    >>> b
    [1, [1, 3], 3]
    >>> a[1].append(3)
    >>> b
    [1, [1, 3, 3], 3]
    <>>> a
    [1, [1, 3, 3], 3]
    深拷貝:拷貝對象及其子對象(父, 子對象不同)
    >>> a = [1,[1,2],3]
    >>> import copy
    >>> b = copy.deepcopy(a)
    >>> a[1].append(3)
    >>> b
    [1, [1, 2], 3]
    >>> a
    [1, [1, 2, 3], 3]

    如何進行實現:

    deepcopy優化版:
    class FiveCardStudInfo(roomai.abstract.AbstractInfo):
        public_state = None
        person_state = None
        def __deepcopy__(self, memodict={}):
            info = FiveCardStudInfo()
            info.public_state = self.public_state.__deepcopy__()
            info.public_state = self.person_state.__deepcopy__()
            return info

     由於深拷貝需要維護一個 memo 用於記錄已經拷貝的對象,所以這也是它比較慢的原因

OS模塊 ( 3 )

  1. 你知道哪些OS模塊的方法
    os.remove(‘path/filename’)  # 刪除文件
    os.rename(oldname, newname) # 重命名文件
    os.walk()   # 生成目錄樹下的所有文件名
    os.chdir('dirname') # 改變目錄
    os.getcwd() # 取得當前工作目錄
    os.path.getsize()   # 返回文件大小
    
  2. 創建、刪除文件

    1. # 創建一個文件
    2. open("chao.txt","w",encoding="utf-8")
    3. import os
      #刪除文件
    4. os.remove("chao.txt")
    
  3. 給出路徑找文件

    
    --------------------------------( 方法一 )------------------------------
    使用os.walk:
    file-- 是你所要便利的目錄的地址, 返回的是一個三元組(root,dirs,files)。
    
    root 所指的是當前正在遍歷的這個文件夾的本身的地址
    dirs 是一個 list ,內容是該文件夾中所有的目錄的名字(不包括子目錄)
    files 同樣是 list , 內容是該文件夾中所有的文件(不包括子目錄)
    def open_2(file):
    
        for root, dirs , files in os.walk(file):
            print("ss",files)
            for filename in files:
                print(os.path.abspath(os.path.join(root, filename)))   #返回絕對路徑
    
    open_2("F:\搜索")
    
    
    --------------------------------( 方法二 )------------------------------
    import os
    def open(files):
    
        for dir_file in os.listdir(files):
            # print("ss",dir_file)   #遞歸獲取所有文件夾和文件
            files_dir_file = os.path.join(files, dir_file) 
    
            if os.path.isdir(files_dir_file):  #是不是文件夾
                open(files_dir_file)
            else:
                print(files_dir_file)
    
    open("F:\搜索")
    
    並將下面的所有文件內容寫入到一個文件中
    def open_2(file):
        for root, dirs , files in os.walk(file):
            for filename in files:
                with open(os.path.abspath(os.path.join(root, filename)), "r") as f:
                    for i in f.readlines():
                        print(i)
                        with open("./cao.txt","a",encoding="utf-8") as f2:
                            f2.write(i)
                            f2.write("\n")
    open_2("F:\搜索")
  4. 使用python打印路徑下的所有文件
    
    # 方法一:(面試要求不使用os.walk)
    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)
                
    # 方法二:(使用os.walk)
    def print_directory_contents(sPath):
        import os
        for root, _, filenames in os.walk(sPath):
            for filename in filenames:
                print(os.path.abspath(os.path.join(root, filename)))
    
    print_directory_contents('.')
    
    
  5. 如何使⽤python刪除⼀個⽂件

    
    import os
    file = r'D:\test.txt'
    if os.path.exists(file):
        os.remove(file)
        print('delete success')
    else:
        print('no such file:%s' % file)
    
  6. 123

random模塊

  • 如何⽣成⼀個隨機數?
    import random
     
    print(random.random())          # 用於生成一個0到1的隨機符點數: 0 <= n < 1.0
    print(random.randint(1, 1000))  # 用於生成一個指定范圍內的整數
    
  • 123
  • 123

co

re模塊 ( 4 )

  1. re模塊的基本方法:
    .     匹配除換行符以外的任意字符
    \w    匹配字母或數字或下划線
    \s    匹配任意的空白符
    \d    匹配數字
    \n    匹配一個換行符
    \t    匹配一個制表符
    \b    匹配一個單詞的結尾
    ^     匹配字符串的開始
    $     匹配字符串的結尾
    \W    
    匹配非字母或數字或下划線
    \D    
    匹配非數字
    \S    
    匹配非空白符
    a|b    
    匹配字符a或字符b
    ()    
    匹配括號內的表達式,也表示一個組
    [...]    
    匹配字符組中的字符
    [^...]    
    匹配除了字符組中字符的所有字符
     
    
    用法說明
    *    重復零次或更多次
    +    重復一次或更多次
    ?    重復零次或一次
    {n}    重復n次
    {n,}    重復n次或更多次
    {n,m}    重復n到m次
    View Code
  2. 手寫正則

    匹配郵箱:
    - [\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])? - \w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
    匹配URL地址: - [a-zA-z]+://[^\s]*
    匹配國內手機號: - \d{3}\d{8}|\d{4}\{7,8}
    匹配身份證號碼: - ^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$
  3. match和search的區別

    - re.match :只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,函數返回None;
    - re.search:匹配整個字符串,直到找到一個匹配。
    
    應用示例:
    import re
    s = "fnfffidvvgf"
    m = re.match("fi",s)
    print(m)
    >>> #None s = re.search("fi",s).group() print(s)
    >>> #fi
  4. 貪婪匹配與非貪婪匹配
    - 匹配0次或多次 <.*>
    - 非貪婪匹配:匹配0次或1次 <.?>
    

functools模塊

  1. 是否使⽤過functools中的函數?其作⽤是什么?
    # 用於修復裝飾器
    import functools
    def deco(func):
        @functools.wraps(func)  # 加在最內層函數正上方
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
     
    @deco
    def index():
        '''哈哈哈哈'''
        x = 10
        print('from index')
     
    print(index.__name__)
    print(index.__doc__)
     
    # 加@functools.wraps
    # index
    # 哈哈哈哈
     
    # 不加@functools.wraps
    # wrapper
    # None
    
    
  2. reduce
    
    在Python 3里,reduce()函數已經被從全局名字空間里移除了,它現在被放置在fucntools模塊里 用的話要 先引入:
    >>> from functools import reduce 
    
    reduce函數,reduce函數會對參數序列中元素進行累積。
    reduce函數的定義:
    reduce(function, sequence[, initial]) -> value
    function參數是一個有兩個參數的函數,reduce依次從sequence中取一個元素,和上一次調用function的結果做參數再次調用function。
    第一次調用function時,如果提供initial參數,會以sequence中的第一個元素和initial作為參數調用function,否則會以序列sequence中的前兩個元素做參數調用function。
    reduce(lambda x, y: x + y, [2, 3, 4, 5, 6], 1)
    結果為21(  (((((1+2)+3)+4)+5)+6)  )
    reduce(lambda x, y: x + y, [2, 3, 4, 5, 6])
    結果為20
    
  3. 123

其他函數

  1. 如何判斷是函數還是方法
    
    from types import FunctionType
    from types import MethodType
    
    print(isinstance(obj.func, FunctionType))   # False
    print(isinstance(obj.func, MethodType))     # True
    

其他

  1. 你知道幾種設計模式

    設計模式分為三大類:
    創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
    結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
    行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
    其實還有兩類:並發型模式和線程池模式。
  2. 編碼和解碼了解過么

  3. 什么是裝飾器,如果想在函數之后進行裝飾應該怎么做
    一個函數,想在運行時動態的增加功能,又不會改動函數本身的代碼

  4. 使用裝飾器的單例模式和使用其他方法的單例,在后續使用中有什么區別

  5. 介紹下垃圾回收機制引用計數 / 分代回收 / 孤立引用環

    引⽤計數機制的優點:
    1、簡單
    2、實時性:⼀旦沒有引⽤,內存就直接釋放了。不⽤像其他機制等到特定時機。實時性還帶來⼀個好處:處理回收內存的時間分攤到了平時。
    引⽤計數機制的缺點:
    1、維護引⽤計數
    2、消耗資源循環引⽤
    list1 = []; list2 =[]
    list1.append(list2); list2.append(list1)
    3、list1與list2相互引⽤,如果不存在其他對象對他們的引用,list1與list2的引用計數也仍然1,所占⽤的內存永遠無法被回收,這將是致命的。
         對於如今的強⼤硬件,缺點1尚可接受,但是循環引⽤導致內存泄露,注定python會將引⼊新的回收機制。(分代收集)
    有三種情況會觸發垃圾回收:
    1、當 gc 模塊的計數器達到閥值的時候,自動回收垃圾
    2、調⽤ gc.collect(),手動回收垃圾
    3、程序退出的時候,python解釋器來回收垃圾
  6. 多進程與多線程的區別CPU密集型應用適合用什么

    多線程可以共享全局變量,多進程不能。多線程中,所有子線程的進程號相同;多進程中,不同的子進程進程號不同。
    python的threading和multiprocessing模塊
  7. 進程通信有哪幾種方式

    無名管道( pipe ): - 管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。
    高級管道(popen): - 將另一個程序當做一個新的進程在當前程序進程中啟動,則它算是當前程序的子進程,這種方式我們成為高級管道方式。
    有名管道(named pipe) : - 有名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。
    消息隊列( message queue ) : - 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。
    信號量( semophore ) :- 信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。
    信號 ( sinal ) : - 信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。
    共享內存( shared memory ) : - 共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。
    套接字( socket ):- 套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同機器間的進程通信。
  8. 介紹下協程,為何比線程還快
    關於GIL鎖的解釋協程的優缺點

  9. 寫出將IP地址127.0.0.1轉換為32位二進制和數的函數
  10. 單向鏈表和雙向鏈表
  11. 寫出將IPv4地址轉換為IPv6的函數
  12. 面向對象的應用場景
    # 需要傳過多的參數:
    class Foo(object):
        def __init__(self, a1, a2, a3, ... , an):
            self.a1 = a1
            self.a2 = a2
                 ...
        def index(self):
            pass
    
    # 給了一些值,對數據進行加工:Django的自定義分頁
    class Foo(object):
        def __init__(self, a1, a2, a3, ... , an):
            self.a1 = a1
            self.a2 = a2
                 ...
        def index(self):
            return self.a1 + self.a2
  13.  
  14. QAQ

RESTful ( 12 )

  1. 談談你對rest api的認識
  2. 用過哪些rest 框架
    - Django的rest_framework
    - 原生CBV
  3. 不使用rest_framework
    利用Django的CBV來實現RESTful,使開發者代碼會多一些。
    通過使用rest_framework框架提高開發效率。
  4. 這個框架使用最多的是什么?
    Serializers
    用戶登錄認證
    分頁
    頻率等
  5. rest_framework視圖中你都用過哪些基類
    GenericAPIView
  6. !rest_framework的GenericAPIView都繼承過哪些類
  7. rest_framework框架有哪些優點?
  8. rest_framework都有哪些組件?
  9. - 路由:自動幫助開發者快速為一個視圖創建四個URL
    - 版本
        - URL
        - GET
        - 請求頭
    - 認證
        - !認證的流程是什么
    - 權限
        - 權限能不能在中間件做
    - 訪問頻率的控制
    - 視圖
    - 解析器:根據Content-Type請求體中的格式數據進行處理。request,data
    - 分頁
    - 序列化
        - 序列化
          - source
          - 定義方法
        - 請求的數據格式校驗
    - 渲染器
  10. 頻率組件是怎么做的
  11. 限制的頻率是多少?
    1分鍾:60-80次/每秒鍾1-2次
  12. 什么是冪等性?
    冪等性:
        一個接口進行一次或多次訪問,對資源不造成影響(是否會對資源造成二次傷害),那么我們就認為這個接口具有冪等性。
    例如:GET:
    putdelete請求
    非冪等性:
        例如:請求等
    具有爭議性的請求:
         patch:
  13. 0
  14. 2

算法排序部分(9)

  1. 手寫快排;堆排;幾種常用排序的算法復雜度是多少;快排平均復雜度多少,最壞情況如何優化;
  2. 手寫:已知一個長度n的無序列表,元素均是數字,要求把所有間隔為d的組合找出來,你寫的解法算法復雜度多少;
  3. 手寫:一個列表A=[A1,A2,…,An],要求把列表中所有的組合情況打印出來;
  4. 手寫:用一行python寫出1+2+3+…+10**8 ;
  5. 手寫python:用遞歸的方式判斷字符串是否為回文;
  6. 單向鏈表長度未知,如何判斷其中是否有環;
  7. 單向鏈表如何使用快速排序算法進行排序;
  8. 手寫:一個長度n的無序數字元素列表,如何求中位數,如何盡快的估算中位數,你的算法復雜度是多少;
  9. 如何遍歷一個內部未知的文件夾(兩種樹的優先遍歷方式)

網絡基礎部分(11)

  1. TCP/IP分別在模型的哪一層;
  2. socket長連接是什么意思;
  3. select和epoll你了解么,區別在哪;
  4. TCP UDP區別;三次握手四次揮手講一下;
    # TCP三次握手
    # 1. 客戶 --> 服務:SYN=1(發起新連接) seq = J(隨機值)
    # 2. 服務 --> 客戶:
    #      SYN=1,
    #      ACK=1(確認接受這次連接請求),
    #      ack=J+1(從廣播的眾多連接請求響應中中發現針對自己的響應,網絡是廣播的)
    #     seq = K
    # 3. 客戶 --> 服務
    #     ACK=1(我知道你接受我了)
    #     ack=K+1(服務端從眾多的連接連理響應中發現針對自己的)
    # 當然,第三次握手消息,服務端也可能沒有接收到,但不可能兩邊一直這樣ACK下
    # 去。但是還可以基於超時時間,重新發起連接請求。
  5. TIME_WAIT過多是因為什么;
  6. http一次連接的全過程:你來說下從用戶發起request——到用戶接收到response時的全過程;
  7. http連接方式。get和post的區別,你還了解其他的方式么;
  8. restful你知道么;
  9. 狀態碼你知道多少,比如200/403/404/504等等# 更多信息跳轉w3
  10. TCP/UDP
  11. socket連接和HTTP連接的區別
  12. Q^Q

HTTP部分( 11 )

  1. 常用的HTTP方法有哪些?
    GET: 用於請求訪問已經被URI(統一資源標識符)識別的資源,可以通過URL傳參給服務器
    POST:用於傳輸信息給服務器,主要功能與GET方法類似,但一般推薦使用POST方式。
    PUT: 傳輸文件,報文主體中包含文件內容,保存到對應URI位置。
    HEAD: 獲得報文首部,與GET方法類似,只是不返回報文主體,一般用於驗證URI是否有效。
    DELETE:刪除文件,與PUT方法相反,刪除對應URI位置的文件。
    OPTIONS:查詢相應URI支持的HTTP方法。
  2. GET方法與POST方法的區別
    區別一:
        - get重點在從服務器上獲取資源,post重點在向服務器發送數據;
    區別二:
        - get傳輸數據是通過URL請求,以field(字段)= value的形式,置於URL后,並用"?"連接,多個請求數據間用"&"連接,
    如http://127.0.0.1/Test/login.action?name=admin&password=admin,這個過程用戶是可見的; - post傳輸數據通過Http的post機制,將字段與對應值封存在請求實體中發送給服務器,這個過程對用戶是不可見的; 區別三: - Get傳輸的數據量小,因為受URL長度限制,但效率較高; - Post可以傳輸大量數據,所以上傳文件時只能用Post方式; 區別四: - get是不安全的,因為URL是可見的,可能會泄露私密信息,如密碼等; - post較get安全性較高; 區別五: - get方式只能支持ASCII字符,向服務器傳的中文字符可能會亂碼。 - post支持標准字符集,可以正確傳遞中文字符。
  3. HTTP請求報文與響應報文格式
    請求報文包含三部分:
        - 請求行:包含請求方法、URI、HTTP版本信息
        - 請求首部字段
        - 請求內容實體
    響應報文包含三部分:
        - 狀態行:包含HTTP版本、狀態碼、狀態碼的原因短語
        - 響應首部字段
        - 響應內容實體
  4. 常見的HTTP相應狀態碼
    200:請求被正常處理
    204:請求被受理但沒有資源可以返回
    206:客戶端只是請求資源的一部分,服務器只對請求的部分資源執行GET方法,相應報文中通過Content-Range指定范圍的資源。
    301:永久性重定向
    302:臨時重定向
    303:與302狀態碼有相似功能,只是它希望客戶端在請求一個URI的時候,能通過GET方法重定向到另一個URI上
    304:發送附帶條件的請求時,條件不滿足時返回,與重定向無關
    307:臨時重定向,與302類似,只是強制要求使用POST方法
    400:請求報文語法有誤,服務器無法識別
    401:請求需要認證
    403:請求的對應資源禁止被訪問
    404:服務器無法找到對應資源
    500:服務器內部錯誤
    503:服務器正忙
  5. HTTP1.1版本新特性
    1. 默認持久連接節省通信量,只要客戶端服務端任意一端沒有明確提出斷開TCP連接,就一直保持連接,可以發送多次HTTP請求
    2. 管線化,客戶端可以同時發出多個HTTP請求,而不用一個個等待響應
    3. 斷點續傳原理
  6. 常見HTTP首部字段
    1. 通用首部字段(請求報文與響應報文都會使用的首部字段)
       - Date:創建報文時間
       - Connection:連接的管理
       - Cache-Control:緩存的控制
       - Transfer-Encoding:報文主體的傳輸編碼方式
    2. 請求首部字段(請求報文會使用的首部字段)
       - Host:請求資源所在服務器
       - Accept:可處理的媒體類型
       - Accept-Charset:可接收的字符集
       - Accept-Encoding:可接受的內容編碼
       - Accept-Language:可接受的自然語言
    3. 響應首部字段(響應報文會使用的首部字段)
       - Accept-Ranges:可接受的字節范圍
       - Location:令客戶端重新定向到的URI
       - Server:HTTP服務器的安裝信息
    4. 實體首部字段(請求報文與響應報文的的實體部分使用的首部字段)
       - Allow:資源可支持的HTTP方法
       - Content-Type:實體主類的類型
       - Content-Encoding:實體主體適用的編碼方式
       - Content-Language:實體主體的自然語言
       - Content-Length:實體主體的的字節數
       - Content-Range:實體主體的位置范圍,一般用於發出部分請求時使用
  7. HTTP與HTTPS的區別
    對傳輸內容加密
    端口: HTTP:80 HTTPS:443
    自定義證書
  8. HTTP的缺點與HTTPS
    1. 通信使用明文不加密,內容可能被竊聽
    2. 不驗證通信方身份,可能遭到偽裝
    3. 無法驗證報文完整性,可能被篡改
    # HTTPS就是HTTP加上加密處理(一般是SSL安全通信線路)+認證+完整性保護
  9. HTTP優化

    利用負載均衡優化和加速HTTP應用

    利用HTTP Cache來優化網站

  10. 從瀏覽器輸入域名網址到看到頁面都發生了什么

    1.瀏覽器向DNS服務器詢問域名對應的IP地址
    
    2.得到域名對應的IP地址后,組裝HTTP請求報文
    
    3.由TCP協議將請求報文分割成多個報文段,可靠的傳給對方
    
    4.由IP協議搜索對方地址,並傳送報文,此過程可能經過多個路由器
    
    5.服務器端的TCP從對方接收到報文
    
    6.服務器端的HTTP解析請求報文,處理並生成響應報文
    
    7.按照相反的順序,將響應報文發回給瀏覽器
    
    8.瀏覽器根據響應報文解析數據(一般為html文檔),並渲染頁面,文檔中也很可能引用了其他資源,這些資源同樣使用HTTP協議想服務器請求
    
  11. 什么是websocket
    websocket是一種類似HTTP的協議:
      - 讓C/S創建鏈接不斷開,以此可以完成:S向C主動推送消息
      - websocket協議額外做的一些前提操作:
        - 握手,連接前進行校驗
        - 發送數據,進行加密
    websocket的本質
        ...
    應用場景:
    5月17日13:19:13,141
      - Django: channel
      - Flask :   gevent-websocket
      - tornado:內置

    QAQ

  12. q^q

數據庫部分( 20 )

  1. MySQL有幾種引擎查詢表數據練習題
    InnoDB:
        - 支持事務
        - 行鎖/表鎖
        - 表鎖:
          - select * from tb for update
        - 行鎖:
          - select * from tb where id=2 for update;
    MyISAM:
        - 全文索引<
        - 表鎖
        - 查詢速度快
        - 表鎖語句:
          - select * from tb for update;

    - Innodb是索引和數據是緊密捆綁的,沒有使用壓縮;
    - 而MyISAM的索引和數據是分開的,並且索引是有壓縮的,內存使用率就對應提高了不少,能加載更多索引,因此,用MyISAM可節省不少硬盤空間。
  2. 數據庫中函數用過哪些?
    聚合函數:max/sum/min/avg
    時間格式化:date_format
    字符串拼接:concat
  3. 索引有哪幾種?區別是什么?
    單列:B+樹/哈希索引  --> 查詢速度快更新速度慢
        - 普通索引 :加速查找
        - 唯一索引 :加速查詢 + 約束(不能重復)
        - 主鍵索引 :加速查詢 + 約束(不能重復) + 不能為空
        - 全文索引 :
    多列:遵循最左前綴規則
        - 聯合索引 :
        - 聯合唯一索引 :
    其他:
    - 索引合並 :利用多個單例索引查詢
        - 覆蓋索引 :在索引表中就能將想要的數據查詢到
        - 組合索引遵循最左前綴規則
            如果組合索引為:(name,email)
            name and email       -- 使用索引
            name                 -- 使用索引
            email                -- 不使用索引
    
  4. 慢日志如何開啟?
    slow_query_log = OFF                 # 是否開啟慢日志記錄
    long_query_time = 2                  # 時間限制,超過此時間,則記錄
    slow_query_log_file = /usr/slow.log  # 日志文件
    log_queries_not_using_indexes = OFF  # 為使用索引的搜索是否記錄
    
  5. MySQL鎖有幾種;死鎖是怎么產生的;
    mysql鎖能在並發情況下的mysql進行更好的優化
    MySQL有三種鎖的級別:頁級、表級、行級,這3種鎖的特性可大致歸納如下: 
    表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
    行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
    頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
    
  6. 為何,以及如何分區、分表;
  7. MySQL的char varchar text的區別;
  8. select的幾種區別
    1. select 1與select * 的區別:
        “selelct 常量 from 表名” 對應所有行,返回的永遠只有一個值,即常量 ,所以一般只用來判斷是否有表記錄;
    而“select * from 表名” 是返回所有行的所有列。
        性能上的差異,關鍵看from和where子句。如果where條件中可以通過索引,那顯然 “selelct 常量 from 表名” 的性能比“select * from 表名” 好。
    2. select count(1) 與select count(*) 的區別 :
        性能上的差異,跟表結構有關系: 
        如果表中沒有主鍵,那么count(1)比count(*)快 
        如果有主鍵,那么count(主鍵,聯合主鍵)比count(*)快 
        如果表中只有一個字段,count(*)最快
    3. select sum(1)的使用:
        select count(*)返回所有滿足條件的記錄數,此時等同於select sum(1) 
        但是sum()可以傳任意數字,負數、浮點數都可以,返回的值是傳入值n*滿足條件記錄數m
  9. 存儲過程和函數的區別
    函數:
        - 參數
        - 返回值:return
    存儲過程:
        - 參數
        - 返回值:out/inout
        - 返回結果集:select * from tb;
  10. 什么是視圖
    虛擬表 --> 通過SQL幫助我們實時查詢數據
  11. 什么是觸發器
    在對表進行 增刪改查 前后定義一些SQL操作
  12. 對前端產生的分頁是如何處理的
    - 數據庫分頁
        存在問題:
            查詢的頁面數越大,速度就會越慢,這是因為每次數據庫都會從第一條開始掃描
            selsct * from tb limit 3 offset 5
            models.User.object.all()[0:10]
    
        解決方法:
            根據業務場景來說:
                1.如果業務對歷史數據不要求的話,就顯示一定的頁數,就可以避免這樣的問題
                2.記錄當前頁數據id的最大最小值,根據記錄的id和需要查詢的范圍來定。
                  但是在url上面會有page的值,如果用戶隨意改url上的頁碼的值的時候,可以參考restfromwork的分頁來做,
    對當前的url進行加密,加密之后它里面就帶了當前頁的最大和最小id,解密出來之后就可以直接拿來用,而且用戶也沒有辦法在url上隨便修改了
  13. 了解join么,有幾種,有何區別,A LEFT JOIN B,查詢的結果中,B沒有的那部分是如何顯示的(NULL);
  14. 寫出SQL語句:獲取一條name="alex"的數據
    select * from tb name='alex' limit 1
  15. BTree索引和hash索引的區別(在磁盤結構上的區別);
  16. 手寫:如何對查詢命令進行優化;
    1. 不用 select *
    2. 固定長度字段列,往前放
    3. char 和 varchar
    4. 固定數據放入內存 choice
    5. 數據庫讀寫分離
    6. 分庫:當數據庫中表過多,將表分到不同的數據庫()
    7. 分表:
        - 水平分表:將某些列拆分到另一張表:博客+博客詳細
        - 垂直分表:將一些歷史信息分到另一張表中:歷史賬單
    8. 緩存:利用redis、memcache進行存儲
        ps:當緩存宕機,如果沒有進行持久化則將所有請求轉接MySQL,
    而MySQL承受不了壓力時會造成無法啟動
    9. 其它 - 慢日志 - 執行計划 10. 分頁
  17. NoSQL了解么,和關系數據庫的區別;
  18. redis有幾種常用存儲類型;
  19. 樂觀鎖和悲觀鎖
  20. 觸發器是什么?
  21. QAQ

Linux部分( 4 )

  1. 講一下你常用的Linux/git命令和作用;
  2. 查看當前進程是用什么命令,除了文件相關的操作外,你平時還有什么操作命令;
  3. Apache和Nginx的區別
  4. 介紹下中間人攻擊:
    # 中間人攻擊(Man-in-the-middle attack,通常縮寫為MITM)是指攻擊者與通訊的兩端分別創建獨立的聯系,並交換其所收到的數據,
    使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個會話都被攻擊者完全控制。
  5. 1

前端部分( 2 )

  1. 你用過什么框架和類庫
    - jQuery
    - BootStrap
    - Vue.js、React、Angular.js
  2. 什么是響應式布局
     通過瀏覽器和設備分辨率的改變做出相應的變化 
    本質是通過 @media屬性來完成:
    <style>
    body{
    margin:0;}
    .pg-header{
    background-color:red;
    height: 48px;}
    @media( min-width: 768px ){
    .pg-header{background-color: green;}}
    @media( min-width: 992px ){
    .pg-header{background-color: pink;}}
    </style>

django項目部分( 19 )

  1. 簡單的介紹下你在公司的項目,不管是不是后端相關的,主要是要體現出你干了什么;
  2. 你在項目中遇到最難的部分是什么,你是怎么解決的;
  3. Django和Flask框架的區別
    Django:
      - 內置很多組件:
        - ORM、admin、Form、ModelForm、中間件、信號、緩存、csrf等
    Flask:
      - 一個輕量級框架內置組件少,可擴展很多第三方組件:
        - flask-session、flask-script、flask-redis、flask-flask-migrate
        - flask-SQLAlchemy、wtforms、blinker
    
    兩個框架都是基於wsgi協議實現的,默認使用的wsgi模塊不一樣,
    還有一個顯著的特點:處理請求的方式不一樣
      - Django:通過將請求封裝成request對象,再通過參數進行傳遞
      - flask:    通過上下文管理實現
    延伸:
      - Django組件
      - flask組件、用途
      - wsgi
      - 上下文管理
  4. MVC / MTV;
  5. Django請求生命周期
    1. wsgi:創建socket服務端,用於接收用戶請求並對請求進行初次封裝
    2. 中間件:對所有請求到來之前,響應之前定制一些操作
    3. 路由: 匹配路由,在url和視圖函數對應關系中,根據當前請求url找到相應的函數
    4. 視圖函數:執行視圖函數,業務處理【通過ORM去數據庫中獲取數據,再去拿到模板,然后將數據和模板進行渲染】
    5. 在經過中間件
    6. 通過wsgi將響應返回給用戶
  6. 什么是wsgi
    是web服務網關接口,是一套協議。以下模塊實現了wsgi協議:
      - wsgiref :性能低,易配置
      - werkzurg
      - uwsgi
    以上模塊本質:實現socket監聽請求,獲取請求后將數據封裝,然后交給web框架處理
    詳解:
    本質是編寫了socket服務端,用來監聽用戶的請求,如果有請求到來,則將請求進行一次封裝然后將【請求】交給web框架來進行下一步處理
  7. 中間件是干嘛的;
    所有請求都要穿過中間件:
      - 對所有的請求進行批量處理
      - 在視圖函數執行之前后進行一些自定義操作。
  8. 你用中間件做過什么;
    - 解決cors跨域請求
    - csrf
      - csrf的本質:
        - 用戶先發送get獲取csrf token:Form表單中一個隱藏的標簽 + cookie
        - 發起post請求時,需要攜帶之前發送給用戶的csrf token;
        - 在中間件的process_view 方法中進行校驗
    
  9. 中間件中有幾個方法分別是什么;(五個方法)
      - process_request(self,request)
      - process_view(self, request, callback, callback_args, callback_kwargs)
      - process_template_response(self,request,response) # 當視圖函數的返回值對象中有render方法時,該方法才會被調用
      - process_exception(self, request, exception)
      - process_response(self, request, response)
    中間件的執行流程: 1 請求先執行所有中間件的process_request,然后做路由匹配,找到函數不執行。 2 再執行所有的process_view,在執行視圖函數。 3 再執行process_response 4 如果程序報錯執行process_exception 5 如果程序有render方法則執行process_template_response
  10. 中間件的應用:
    # 為什么要在中間件用這些:
    - 一些內置組件上的應用:
      - csrf
      - session
         緩存
      - 用戶登錄校驗  # 如果不使用就需要為每個函數添加裝飾器,太過繁瑣。
      - 權限處理     # 用戶登錄后將權限放到session中,然后再每次請求時都需要判斷當前用戶是否有權訪問當前url,這些檢查的東西可以放到中間件中統一處理。
      - session
    - 跨域:
      - 前后端分離時,本地測試開發時使用的 
  11. CSRF原理
    目標:防止用戶直接向服務端發起POST請求。
    方案:先發送GET請求時,將token保存到:cookie、Form表單中(隱藏的input標簽),以后再發送請求時只要攜帶過來即可。
    問題:如果想后台發送POST請求?
       form表單提交:
          <form method="POST">
             {% csrf_token %}
             <input type='text' name='user' />
             <input type='submit' />
          </form>
          
       ajax提交:
          $.ajax({
            url:'/index',
             type:'POST',
             data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'}
          })
          前提:引入jquery + 引入jquery.cookie 
          $.ajax({
             url: 'xx',
             type:'POST',
             data:{name:'oldboyedu'},
             headers:{
                X-CSRFToken: $.cookie('csrftoken')
             },
             dataType:'json', // arg = JSON.parse('{"k1":123}')
             success:function(arg){
                console.log(arg)
             }
          })
    <body>
        <input type="button" onclick="Do1();"  value="Do it"/>
        <input type="button" onclick="Do2();"  value="Do it"/>
        <input type="button" onclick="Do3();"  value="Do it"/>
    
        <script src="/static/jquery-3.3.1.min.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $.ajaxSetup({  // 為所有Ajax請求添加函數
                beforeSend: function(xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
                }
            });
    
             function Do1(){
                $.ajax({
                    url:"/index/",
                    data:{id:1},
                    type:'POST',
                    success:function(data){
                        console.log(data);
                    }
                });
            }
    
             function Do2(){
                $.ajax({
                    url:"/index/",
                    data:{id:1},
                    type:'POST',
                    success:function(data){
                        console.log(data);
                    }
                });
            }
    
             function Do3(){
                $.ajax({
                    url:"/index/",
                    data:{id:1},
                    type:'POST',
                    success:function(data){
                        console.log(data);
                    }
                });
            }
        </script>
    </body>
    優化方案
  12. Django的Form的作用
    1. 幫助我們生成HTML標簽
    2. 對用戶輸入的數據進行校驗
       ps:form對象是個可迭代對象
    Q:從數據庫獲取數據時,下拉框無法實時刷新。
    A:重寫構造方法,在構造方法中重新去獲取數據
         def __str__(self):
             return self.title
  13. 緩存怎么用;
  14. CSRF是什么,django是如何避免的;XSS呢;
  15. 如果你來設計login,簡單的說一下思路;
  16. session和cookie的聯系與區別;session為什么說是安全的;
  17. WSGI和Nginx的作用;
  18. 瀏覽器緩存機制
  19. 你看過django的admin源碼么;看過flask的源碼么;你如何理解開源;
  20. QAQ
  21.  
  22.  

Flask部分( 14 )

  1. FLask和Django的區別
    - 對於Django來說:內部組件全面,自身功能強大,給人一種大而全的感覺,
    ( 你知 或者不知他,Django就在那里,不悲不喜。 你念 或者不念他,功能就在那里,不來不去。 你愛 或者不愛他,組件就在那里,不增不減。 你用,或者不用他,Django就在你手裡。不捨不棄。)
    而Flask:內置組件就很少,但它的第三方組件很多,可擴展性強,還可以自定義組件,
    - 兩個框架本身都沒有寫sockte,都是基於wsgi協議做的,而flask框架中的上下文管理較為耀眼。  - 相同點:它們兩個框架都沒有寫sockte,都是基於wsgi協議做的   請求相關數據傳遞的方式不同:django:通過傳遞request參數取值                 flask:見問題二            組件不同:django組件多                 flask組件少,第三方組件豐富
  2. 談談你對Flask與Django框架的認識
    相同:
        都基於wsgi,
    不同:
        對請求處理不同:Flask基於上下文管理;Django通過傳值來處理
        Django功能多,內置組件全面:缺點不能自定義添加或刪除組件
        Flask內置組件少,但是可以通過第三方組件來擴展:Flask-email,Flask-SQLAlchemy,Flask-session等
    
  3. Flask中的session是什么時候創建,什么時候銷毀的?
      當請求進來時,會將 requset 和 session 封裝為一個 RequestContext 對象,通過 LocalStack 將 RequestContext 放入到Local對象中,
    因為請求第一次來 session 是空值,所以執行 open_session,給 session(uuid4())賦值,再通過視圖函數處理,請求響應時執行save.session,
    將簽名 session 寫入 cookie 中,再將 Local 中的數值pop掉。
  4. Flask為什么把請求放到RequestContext中?
        因為 request 和 session 都是在視圖中操作頻繁的數據,也是用戶請求需要用的數據,
    將 request 和 session 封裝在 RequestContext 中 top,pop 一次就可以完成,而單獨不封裝在一起就會多次操作,
    
  5. flask中一共有幾個LocalStack和Local對象
    兩個LocalStack,兩個Local:
      - request、session 共同用一個 LocalStack 和 Local
      - g、app 共同用一個 Localstack 和 Local
    
  6. Flask上下文管理是如何實現的:
    - 前提:記得不太清楚了,/or 最近剛看過
     簡單來說,falsk上下文管理可以分為三個階段:
      1、請求進來時,將請求相關的數據放入上下文管理中
      2、在視圖函數中,要去上下文管理中取值
      3、請求響應,要將上下文管理中的數據清除
     詳細點來說:
      1、請求剛進來,將request,session封裝在RequestContext類中,app,g封裝在AppContext類中,並通過LocalStack將requestcontext和appcontext放入Local類中
      2、視圖函數中,通過localproxy--->偏函數--->localstack--->local取值
      3、請求相應時,先執行save.session()再各自執行pop(),將local中的數據清除
    
  7. Local的作用?
    - 用於保存:
        - 請求上下文對象
        - App上下文對象
    - 並且可以做到"線程"間的數據隔離。
    線程:threading.local
    協程:greenlet.get_current as get_get_ident
    - localstack 的源碼與 threading.local(線程處理)的作用相似,
      不同之處是 Local 是通過 greenlet(協程)獲取唯一標識,粒度更細
    
  8. LocalStack的作用?
    將local對象中的數據維護成一個棧【ctx,ctx】(先進后出)
    {
        “協程或線程的唯一標識”: { stack:[ctx,ctx,ctx,] }
    }
  9. 為什么要將Local對象中的數據維護成一個棧
    當是web應用時:不管是單線程還是多線程,棧中只有一個數據
      - 服務端單線程:
      {
          111:{stack: [ctx, ]}
      }
      - 服務端多線程:
      {
          111:{stack: [ctx, ]}
          112:{stack: [ctx, ]}
      }
    離線腳本:可以在棧中放入多個數據,在任何情況下都可以獲取到當前app的請求和響應
    with app01.app_context():
    print(current_app)
         with app02.app_context(): 
              print(current_app)
          print(current_app)
    
  10. 什么是G?
      - G 相當於一次請求的全局變量,當請求進來時將 G 和 current_app 封裝為一個 APPContext 類,在通過 LocalStack 將 Appcontext 放入 Local 中,
    取值時通過偏函數,LocalStack、loca 中取值,響應時將 Local 中的 g 數據刪除:
    - 應用場景:
    befor_request + G = 權限認證系統
  11. 如何獲取session/g
    通過 、偏函數(lookup_req_object)、Localstack、Local 取值
  12. Flask內置功能:
    - 內置組件
      - 配置 - 路由 - 視圖
      - 模板 - session - 藍圖 
      - 閃現 - 裝飾器 - 中間件
    - 第三方組件
      - Flask-session    # 將原來保存在cookie中的session數據,放到Redis/memcache/文件/數據庫中
      - Flask-migrate    # 做數據庫遷移
      - Flask-script     # 
      - Flask-SQLAlchemy # ORM
      - blinker
    - 公共:
      - DButils        # 數據庫連接池:  兩種模式; 為每個參數設置一個連接/共享一個連接;全局參數
      - wtforms        # form組件:做表單驗證+生成HTML標簽
      - gevent-websocket
    - 自定義組件:
      - flask-login
  13. 手寫:自己寫一個類+列表, 實現棧的功能(LocalStack)
    分組函數 : group by 字段  having   判斷條件   (固定語法)分組和聚合函數搭配
    分組函數 : group by 字段  having   判斷條件   (固定語法)分組和聚合函數搭配
    class Stack():
        def __init__(self,size):
            self.size=size
            self.stack=[]
    
        def getstack(self):
            """
            #獲取棧當前數據
            :return:
            """
            return self.stack
    
        def __str__(self):
            return str(self.stack)
    
        def top(self,x):
        # 入棧之前檢查棧是否已滿
            if self.isfull():
                raise Exception("stack is full")
            else:
                self.stack.append(x)
    
        def pop(self):
            """
            # 出棧之前檢查棧是否已空
            :return:
            """
            if self.isempty():
                raise Exception("stack is empty")
            else:
                self.stack.pop()
    
        def isfull(self):
            """
            判斷棧滿
            :return:
            """
            if len(self.stack)==self.size:
                return True
            return False
    
        def isempty(self):
            """
            判斷棧空
            :return:
            """
            if len(self.stack)==0:
                return True
            return False
    
    if __name__ == '__main__' :
        stack=Stack(4)
    
        for i in range(11):
            stack.top(i)
            print(stack.getstack())
    
        for i in range(3):
            stack.pop()
            print(stack.getstack())
    
    View Code
  14. 什么是threading.local,以及他的作用
  15. 原生SQL和ORM的區別
    
    # 關系對象映射,本質是
     - SQL
       - 執行效率更高,但是代碼更多,開發效率低
     - ORM
       - 開發效率高,編寫速度快,執行效率相比於優化后的SQL較低些
    
  16. 反射在哪里用到過

Redis (  )

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM