2019 Python 面試 100 問

如下內容出自小程序「編程面試題庫」,本文首發於公衆號「zone7」

0 遇到過得反爬蟲策略以及解決方法?

1.經過headers反爬蟲 2.基於用戶行爲的發爬蟲:(同一IP短期內訪問的頻率) 3.動態網頁反爬蟲(經過ajax請求數據,或者經過JavaScript生成) 4.對部分數據進行加密處理的(數據是亂碼)html

解決方法:

對於基本網頁的抓取能夠自定義headers,添加headers的數據 使用多個代理ip進行抓取或者設置抓取的頻率下降一些, 動態網頁的可使用selenium + phantomjs 進行抓取 對部分數據進行加密的,可使用selenium進行截圖,使用python自帶的pytesseract庫進行識別,可是比較慢最直接的方法是找到加密的方法進行逆向推理。python

1 urllib 和 urllib2 的區別?

  • urllib 和urllib2都是接受URL請求的相關模塊,可是urllib2能夠接受一個Request類的實例來設置URL請求的headers,urllib僅能夠接受URL。urllib不能夠假裝你的User-Agent字符串。
  • urllib提供urlencode()方法用來GET查詢字符串的產生,而urllib2沒有。這是爲什麼urllib常和urllib2一塊兒使用的緣由。

2 列舉網絡爬蟲所用到的網絡數據包,解析包?

  • 網絡數據包 urllib、urllib二、requests
  • 解析包 re、xpath、beautiful soup、lxml

3 簡述一下爬蟲的步驟?

  1. 肯定需求;
  2. 肯定資源;
  3. 經過url獲取網站的返回數據;
  4. 定位數據;
  5. 存儲數據。

4 遇到反爬機制怎麼處理?

反爬機制:

headers方向 判斷User-Agent、判斷Referer、判斷Cookie。 將瀏覽器的headers信息所有添加進去 注意:Accept-Encoding;gzip,deflate須要註釋掉react

5 常見的HTTP方法有哪些?

  • GET:請求指定的頁面信息,返回實體主體;
  • HEAD:相似於get請求,只不過返回的響應中沒有具體的內容,用於捕獲報頭;
  • POST:向指定資源提交數據進行處理請求(好比表單提交或者上傳文件),。數據被包含在請求體中。
  • PUT:從客戶端向服務端傳送數據取代指定的文檔的內容;
  • DELETE:請求刪除指定的頁面;
  • CONNNECT:HTTP1.1協議中預留給可以將鏈接方式改成管道方式的代理服務器;
  • OPTIONS:容許客戶端查看服務器的性能; TRACE:回顯服務器的請求,主要用於測試或者診斷。

6 說一說redis-scrapy中redis的做用?

它是將scrapy框架中Scheduler替換爲redis數據庫,實現隊列管理共享。jquery

優勢:

  1. 能夠充分利用多臺機器的帶寬;
  2. 能夠充分利用多臺機器的IP地址。

7 遇到的反爬蟲策略以及解決方法?

  1. 經過headers反爬蟲:自定義headers,添加網頁中的headers數據。
  2. 基於用戶行爲的反爬蟲(封IP):可使用多個代理IP爬取或者將爬取的頻率下降。
  3. 動態網頁反爬蟲(JS或者Ajax請求數據):動態網頁可使用 selenium + phantomjs 抓取。
  4. 對部分數據加密處理(數據亂碼):找到加密方法進行逆向推理。

8 若是讓你來防範網站爬蟲,你應該怎麼來提升爬取的難度 ?

  1. 判斷headers的User-Agent;
  2. 檢測同一個IP的訪問頻率;
  3. 數據經過Ajax獲取;
  4. 爬取行爲是對頁面的源文件爬取,若是要爬取靜態網頁的html代碼,可使用jquery去模仿寫html。

9 scrapy分爲幾個組成部分?分別有什麼做用?

分爲5個部分;Spiders(爬蟲類),Scrapy Engine(引擎),Scheduler(調度器),Downloader(下載器),Item Pipeline(處理管道)。web

  • Spiders:開發者自定義的一個類,用來解析網頁並抓取指定url返回的內容。
  • Scrapy Engine:控制整個系統的數據處理流程,並進行事務處理的觸發。
  • Scheduler:接收Engine發出的requests,並將這些requests放入處處理列隊中,以便以後engine須要時再提供。
  • Download:抓取網頁信息提供給engine,進而轉發至Spiders。
  • Item Pipeline:負責處理Spiders類提取以後的數據。 好比清理HTML數據、驗證爬取的數據(檢查item包含某些字段)、查重(並丟棄)、將爬取結果保存到數據庫中

10 簡述一下scrapy的基本流程?

image

scrapy分爲9個步驟:

  1. Spiders須要初始的start_url或則函數stsrt_requests,會在內部生成Requests給Engine;
  2. Engine將requests發送給Scheduler;
  3. Engine從Scheduler那獲取requests,交給Download下載;
  4. 在交給Dowmload過程當中會通過Downloader Middlewares(通過process_request函數);
  5. Dowmloader下載頁面後生成一個response,這個response會傳給Engine,這個過程當中又通過了Downloader Middlerwares(通過process_request函數),在傳送中出錯的話通過process_exception函數;
  6. Engine將從Downloader那傳送過來的response發送給Spiders處理,這個過程通過Spiders Middlerwares(通過process_spider_input函數);
  7. Spiders處理這個response,返回Requests或者Item兩個類型,傳給Engine,這個過程又通過Spiders Middlewares(通過porcess_spider_output函數);
  8. Engine接收返回的信息,若是使Item,將它傳給Items Pipeline中;若是是Requests,將它傳給Scheduler,繼續爬蟲;
  9. 重複第三步,直至沒有任何須要爬取的數據

11 python3.5語言中enumerate的意思是

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

12 你是否瞭解谷歌的無頭瀏覽器?

無頭瀏覽器即headless browser,是一種沒有界面的瀏覽器。既然是瀏覽器那麼瀏覽器該有的東西它都應該有,只是看不到界面而已。ajax

Python中selenium模塊中的PhantomJS即爲無界面瀏覽器(無頭瀏覽器):是基於QtWebkit的無頭瀏覽器。redis

13 scrapy和scrapy-redis的區別?

scrapy是一個爬蟲通用框架,但不支持分佈式,scrapy-redis是爲了更方便的實現scrapy分佈式爬蟲,而提供了一些以redis爲基礎的組件算法

爲何會選擇redis數據庫?

由於redis支持主從同步,並且數據都是緩存在內存中,因此基於redis的分佈式爬蟲,對請求和數據的高頻讀取效率很是高shell

什麼是主從同步?

在Redis中,用戶能夠經過執行SLAVEOF命令或者設置slaveof選項,讓一個服務器去複製(replicate)另外一個服務器,咱們稱呼被複制的服務器爲主服務器(master),而對主服務器進行復制的服務器則被稱爲從服務器(slave),當客戶端向從服務器發送SLAVEOF命令,要求從服務器複製主服務器時,從服務器首先須要執行同步操做,也便是,將從服務器的數據庫狀態更新至主服務器當前所處的數據庫狀態

14 scrapy的優缺點?爲何要選擇scrapy框架?

優勢:

採起可讀性更強的xpath代替正則 強大的統計和log系統 同時在不一樣的url上爬行 支持shell方式,方便獨立調試 寫middleware,方便寫一些統一的過濾器 經過管道的方式存入數據庫

缺點:

基於python爬蟲框架,擴展性比較差,基於twisted框架,運行中exception是不會幹掉reactor,而且異步框架出錯後是不會停掉其餘任務的,數據出錯後難以察覺

15 scrapy和requests的使用狀況?

requests 是 polling 方式的,會被網絡阻塞,不適合爬取大量數據

scapy 底層是異步框架 twisted ,併發是最大優點

16 描述一下scrapy框架的運行機制?

從start_urls裏面獲取第一批url發送請求,請求由請求引擎給調度器入請求對列,獲取完畢後,調度器將請求對列交給下載器去獲取請求對應的響應資源,並將響應交給本身編寫的解析方法作提取處理,若是提取出須要的數據,則交給管道處理,若是提取出url,則繼續執行以前的步驟,直到多列裏沒有請求,程序結束。

17 寫爬蟲使用多進程好,仍是用多線程好?

IO密集型代碼(文件處理、網絡爬蟲等),多線程可以有效提高效率(單線程下有IO操做會進行IO等待,形成沒必要要的時間浪費,而開啓多線程能在線程A等待時,自動切換到線程B,能夠不浪費CPU的資源,從而能提高程序執行效率)。在實際的數據採集過程當中,既考慮網速和響應的問題,也須要考慮自身機器的硬件狀況,來設置多進程或多線程

18 常見的反爬蟲和應對方法?

  1. 基於用戶行爲,同一個ip段時間屢次訪問同一頁面        利用代理ip,構建ip池
  2. 請求頭裏的user-agent        構建user-agent池(操做系統、瀏覽器不一樣,模擬不一樣用戶)
  3. 動態加載(抓到的數據和瀏覽器顯示的不同),js渲染    模擬ajax請求,返回json形式的數據
  4. selenium / webdriver 模擬瀏覽器加載
  5. 對抓到的數據進行分析
  6. 加密參數字段     會話跟蹤【cookie】      防盜鏈設置【Referer

19 分佈式爬蟲主要解決什麼問題?

面對海量待抓取網頁,只有採用分佈式架構,纔有可能在較短期內完成一輪抓取工做。

它的開發效率是比較快並且簡單的。

20 如何提升爬取效率?

爬蟲下載慢主要緣由是阻塞等待發往網站的請求和網站返回

1,採用異步與多線程,擴大電腦的cpu利用率;

    2,採用消息隊列模式

    3,提升帶寬
複製代碼

21 說說什麼是爬蟲協議?

Robots協議(也稱爲爬蟲協議、爬蟲規則、機器人協議等)也就是robots.txt,網站經過robots協議告訴搜索引擎哪些頁面能夠抓取,哪些頁面不能抓取。

Robots協議是網站國際互聯網界通行的道德規範,其目的是保護網站數據和敏感信息、確保用戶我的信息和隱私不被侵犯。因其不是命令,故須要搜索引擎自覺遵照。

22 若是對方網站反爬取,封IP了怎麼辦?

  1. 放慢抓取熟速度,減少對目標網站形成的壓力,可是這樣會減小單位時間內的數據抓取量
  2. 使用代理IP(免費的可能不穩定,收費的可能不划算)

23 有一個jsonline格式的文件file

def get_lines():
    with open('file.txt','rb') as f:
        return f.readlines()

if __name__ == '__main__':
    for e in get_lines():
        process(e) # 處理每一行數據
複製代碼

如今要處理一個大小爲10G的文件,可是內存只有4G,若是在只修改get_lines 函數而其餘代碼保持不變的狀況下,應該如何實現?須要考慮的問題都有那些?

def get_lines():
    with open('file.txt','rb') as f:
        for i in f:
            yield i
複製代碼

Pandaaaa906提供的方法

from mmap import mmap


def get_lines(fp):
    with open(fp,"r+") as f:
        m = mmap(f.fileno(), 0)
        tmp = 0
        for i, char in enumerate(m):
            if char==b"\n":
                yield m[tmp:i+1].decode()
                tmp = i+1

if __name__=="__main__":
    for i in get_lines("fp_some_huge_file"):
        print(i)
複製代碼

要考慮的問題有:內存只有4G沒法一次性讀入10G文件,須要分批讀入分批讀入數據要記錄每次讀入數據的位置。分批每次讀取數據的大小,過小會在讀取操做花費過多時間。 stackoverflow.com/questions/3…

24 補充缺失的代碼

def print_directory_contents(sPath):
""" 這個函數接收文件夾的名稱做爲輸入參數 返回該文件夾中文件的路徑 以及其包含文件夾中文件的路徑 """
import os
for s_child in os.listdir(s_path):
    s_child_path = os.path.join(s_path, s_child)
    if os.path.isdir(s_child_path):
        print_directory_contents(s_child_path)
    else:
        print(s_child_path)
複製代碼

25 輸入日期, 判斷這一天是這一年的第幾天?

import datetime
def dayofyear():
    year = input("請輸入年份: ")
    month = input("請輸入月份: ")
    day = input("請輸入天: ")
    date1 = datetime.date(year=int(year),month=int(month),day=int(day))
    date2 = datetime.date(year=int(year),month=1,day=1)
    return (date1-date2).days+1
複製代碼

26 打亂一個排好序的list對象alist?

import random
alist = [1,2,3,4,5]
random.shuffle(alist)
print(alist)
複製代碼

27 現有字典 d= {'a':24,'g':52,'i':12,'k':33}請按value值進行排序?

sorted(d.items(),key=lambda x:x[1])
複製代碼

28 字典推導式

d = {key:value for (key,value) in iterable}
複製代碼

29 請反轉字符串 "aStr"?

print("aStr"[::-1])
複製代碼

30 將字符串 "k:1 |k1:2|k2:3|k3:4",處理成字典 {k:1,k1:2,

str1 = "k:1|k1:2|k2:3|k3:4"
def str2dict(str1):
    dict1 = {}
    for iterms in str1.split('|'):
        key,value = iterms.split(':')
        dict1[key] = value
    return dict1
#字典推導式
d = {k:int(v) for t in str1.split("|") for k, v in (t.split(":"), )}
複製代碼

31 請按alist中元素的age由大到小排序

alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
    return sorted(alist,key=lambda x:x['age'],reverse=True)
複製代碼

32 下面代碼的輸出結果將是什麼?

list = ['a','b','c','d','e']
print(list[10:])
複製代碼

代碼將輸出[],不會產生IndexError錯誤,就像所指望的那樣,嘗試用超出成員的個數的index來獲取某個列表的成員。例如,嘗試獲取list[10]和以後的成員,會致使IndexError。然而,嘗試獲取列表的切片,開始的index超過了成員個數不會產生IndexError,而是僅僅返回一個空列表。這成爲特別讓人噁心的疑難雜症,由於運行的時候沒有錯誤產生,致使Bug很難被追蹤到。

33 寫一個列表生成式,產生一個公差爲11的等差數列

print([x*11 for x in range(10)])
複製代碼

34 給定兩個列表,怎麼找出他們相同的元素和不一樣的元素?

list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)
print(set1 ^ set2)
複製代碼

35 請寫出一段python代碼實現刪除list裏面的重複元素?

l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
print(l2)
複製代碼

用list類的sort方法:

l1 = ['b','c','d','c','a','a']
l2 = list(set(l1))
l2.sort(key=l1.index)
print(l2)
複製代碼

也能夠這樣寫:

l1 = ['b','c','d','c','a','a']
l2 = sorted(set(l1),key=l1.index)
print(l2)
複製代碼

也能夠用遍歷:

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

36 給定兩個list A,B ,請用找出A,B中相同與不一樣的元素

A,B 中相同元素: print(set(A)&set(B))
A,B 中不一樣元素:  print(set(A)^set(B))
複製代碼

37 python新式類和經典類的區別?

a. 在python裏凡是繼承了object的類,都是新式類

b. Python3裏只有新式類

c. Python2裏面繼承object的是新式類,沒有寫父類的是經典類

d. 經典類目前在Python裏基本沒有應用

38 python中內置的數據結構有幾種?

a. 整型 int、 長整型 long、浮點型 float、 複數 complex

b. 字符串 str、 列表 list、 元祖 tuple

c. 字典 dict 、 集合 set

d. Python3 中沒有 long,只有無限精度的 int

39 python如何實現單例模式?請寫出兩種實現方式?

第一種方法:使用裝飾器

def singleton(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper
    
    
@singleton
class Foo(object):
    pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)  # True
複製代碼

第二種方法:使用基類 New 是真正建立實例對象的方法,因此重寫基類的new 方法,以此保證建立對象的時候只生成一個實例

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
    
    
class Foo(Singleton):
    pass

foo1 = Foo()
foo2 = Foo()

print(foo1 is foo2)  # True
複製代碼

第三種方法:元類,元類是用於建立類對象的類,類對象建立實例對象時必定要調用call方法,所以在調用call時候保證始終只建立一個實例便可,type是python的元類

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance


# Python2
class Foo(object):
    __metaclass__ = Singleton

# Python3
class Foo(metaclass=Singleton):
    pass

foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)  # True

複製代碼

40 反轉一個整數,例如-123 --> -321

class Solution(object):
    def reverse(self,x):
        if -10<x<10:
            return x
        str_x = str(x)
        if str_x[0] !="-":
            str_x = str_x[::-1]
            x = int(str_x)
        else:
            str_x = str_x[1:][::-1]
            x = int(str_x)
            x = -x
        return x if -2147483648<x<2147483647 else 0
if __name__ == '__main__':
    s = Solution()
    reverse_int = s.reverse(-120)
    print(reverse_int)
複製代碼

41 設計實現遍歷目錄與子目錄,抓取.pyc文件?

第一種方法:

import os

def get_files(dir,suffix):
    res = []
    for root,dirs,files in os.walk(dir):
        for filename in files:
            name,suf = os.path.splitext(filename)
            if suf == suffix:
                res.append(os.path.join(root,filename))

    print(res)

get_files("./",'.pyc')
複製代碼

第二種方法:

import os

def pick(obj):
    if ob.endswith(".pyc"):
        print(obj)

def scan_path(ph):
    file_list = os.listdir(ph)
    for obj in file_list:
        if os.path.isfile(obj):
    pick(obj)
        elif os.path.isdir(obj):
            scan_path(obj)

if __name__=='__main__':
    path = input('輸入目錄')
    scan_path(path)
複製代碼

第三種方法

from glob import iglob


def func(fp, postfix):
    for i in iglob(f"{fp}/**/*{postfix}", recursive=True):
        print(i)

if __name__ == "__main__":
    postfix = ".pyc"
    func("K:\Python_script", postfix)
複製代碼

42 Python-遍歷列表時刪除元素的正確作法

遍歷在新在列表操做,刪除時在原來的列表操做

a = [1,2,3,4,5,6,7,8]
print(id(a))
print(id(a[:]))
for i in a[:]:
    if i>5:
        pass
    else:
        a.remove(i)
    print(a)
print('-----------')
print(id(a))

複製代碼
#filter
a=[1,2,3,4,5,6,7,8]
b = filter(lambda x: x>5,a)
print(list(b))
複製代碼

列表解析

a=[1,2,3,4,5,6,7,8]
b = [i for i in a if i>5]
print(b)
複製代碼

倒序刪除 由於列表老是‘向前移’,因此能夠倒序遍歷,即便後面的元素被修改了,尚未被遍歷的元素和其座標仍是保持不變的

a=[1,2,3,4,5,6,7,8]
print(id(a))
for i in range(len(a)-1,-1,-1):
    if a[i]>5:
        pass
    else:
        a.remove(a[i])
print(id(a))
print('-----------')
print(a)
複製代碼

43 字符串的操做題目

全字母短句 PANGRAM 是包含全部英文字母的句子,好比:A QUICK BROWN FOX JUMPS OVER THE LAZY DOG. 定義並實現一個方法 get_missing_letter, 傳入一個字符串採納數,返回參數字符串變成一個 PANGRAM 中所缺失的字符。應該忽略傳入字符串參數中的大小寫,返回應該都是小寫字符並按字母順序排序(請忽略全部非 ACSII 字符)

下面示例是用來解釋,雙引號不須要考慮:

(0)輸入: "A quick brown for jumps over the lazy dog"

返回: ""

(1)輸入: "A slow yellow fox crawls under the proactive dog"

返回: "bjkmqz"

(2)輸入: "Lions, and tigers, and bears, oh my!"

返回: "cfjkpquvwxz"

(3)輸入: ""

返回:"abcdefghijklmnopqrstuvwxyz"

def get_missing_letter(a):
    s1 = set("abcdefghijklmnopqrstuvwxyz")
    s2 = set(a)
    ret = "".join(sorted(s1-s2))
    return ret
    
print(get_missing_letter("python"))
複製代碼

44 可變類型和不可變類型

1,可變類型有list,dict.不可變類型有string,number,tuple.

2,當進行修改操做時,可變類型傳遞的是內存中的地址,也就是說,直接修改內存中的值,並無開闢新的內存。

3,不可變類型被改變時,並無改變原內存地址中的值,而是開闢一塊新的內存,將原地址中的值複製過去,對這塊新開闢的內存中的值進行操做。

45 is和==有什麼區別?

is:比較的是兩個對象的id值是否相等,也就是比較倆對象是否爲同一個實例對象。是否指向同一個內存地址

== : 比較的兩個對象的內容/值是否相等,默認會調用對象的eq()方法

46 求出列表全部奇數並構造新列表

a = [1,2,3,4,5,6,7,8,9,10]
res = [ i for i in a if i%2==1]
print(res)
複製代碼

47 用一行python代碼寫出1+2+3+10248

from functools import reduce
#1.使用sum內置求和函數
num = sum([1,2,3,10248])
print(num)
#2.reduce 函數
num1 = reduce(lambda x,y :x+y,[1,2,3,10248])
print(num1)
複製代碼

48 Python中變量的做用域?(變量查找順序)

函數做用域的LEGB順序

1.什麼是LEGB?

L: local 函數內部做用域

E: enclosing 函數內部與內嵌函數之間

G: global 全局做用域

B: build-in 內置做用

python在函數裏面的查找分爲4種,稱之爲LEGB,也正是按照這是順序來查找的

49 字符串 "123" 轉換成 123,不使用內置api,例如 int()

方法一: 利用 str 函數

def atoi(s):
    num = 0
    for v in s:
        for j in range(10):
            if v == str(j):
                num = num * 10 + j
    return num
複製代碼

方法二: 利用 ord 函數

def atoi(s):
    num = 0
    for v in s:
        num = num * 10 + ord(v) - ord('0')
    return num
複製代碼

方法三: 利用 eval 函數

def atoi(s):
    num = 0
    for v in s:
        t = "%s * 1" % v
        n = eval(t)
        num = num * 10 + n
    return num
複製代碼

方法四: 結合方法二,使用 reduce,一行解決

from functools import reduce
def atoi(s):
    return reduce(lambda num, v: num * 10 + ord(v) - ord('0'), s, 0)
複製代碼

50 Given an array of integers

給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。你能夠假設每一個輸入只對應一種答案,且一樣的元素不能被重複利用。示例:給定nums = [2,7,11,15],target=9 由於 nums[0]+nums[1] = 2+7 =9,因此返回[0,1]

class Solution:
    def twoSum(self,nums,target):
        """ :type nums: List[int] :type target: int :rtype: List[int] """
        d = {}
        size = 0
        while size < len(nums):
            if target-nums[size] in d:
                if d[target-nums[size]] <size:
                    return [d[target-nums[size]],size]
                else:
                    d[nums[size]] = size
                size = size +1
solution = Solution()
list = [2,7,11,15]
target = 9
nums = solution.twoSum(list,target)
print(nums)
複製代碼

給列表中的字典排序:假設有以下list對象,alist=[{"name":"a","age":20},{"name":"b","age":30},{"name":"c","age":25}],將alist中的元素按照age從大到小排序 alist=[{"name":"a","age":20},{"name":"b","age":30},{"name":"c","age":25}]

alist_sort = sorted(alist,key=lambda e: e.__getitem__('age'),reverse=True)
複製代碼

51 python代碼實現刪除一個list裏面的重複元素

def distFunc1(a):
    """使用集合去重"""
    a = list(set(a))
    print(a)

def distFunc2(a):
    """將一個列表的數據取出放到另外一個列表中,中間做判斷"""
    list = []
    for i in a:
        if i not in list:
            list.append(i)
    #若是須要排序的話用sort
    list.sort()
    print(list)

def distFunc3(a):
    """使用字典"""
    b = {}
    b = b.fromkeys(a)
    c = list(b.keys())
    print(c)

if __name__ == "__main__":
    a = [1,2,4,2,4,5,7,10,5,5,7,8,9,0,3]
    distFunc1(a)
    distFunc2(a)
    distFunc3(a)
  
複製代碼

52 統計一個文本中單詞頻次最高的10個單詞?

import re

# 方法一
def test(filepath):
    
    distone = {}

    with open(filepath) as f:
        for line in f:
            line = re.sub("\W+", " ", line)
            lineone = line.split()
            for keyone in lineone:
                if not distone.get(keyone):
                    distone[keyone] = 1
                else:
                    distone[keyone] += 1
    num_ten = sorted(distone.items(), key=lambda x:x[1], reverse=True)[:10]
    num_ten =[x[0] for x in num_ten]
    return num_ten
    
 
# 方法二 
# 使用 built-in 的 Counter 裏面的 most_common
import re
from collections import Counter


def test2(filepath):
    with open(filepath) as f:
        return list(map(lambda c: c[0], Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))
複製代碼

53 請寫出一個函數知足如下條件

該函數的輸入是一個僅包含數字的list,輸出一個新的list,其中每個元素要知足如下條件:

一、該元素是偶數

二、該元素在原list中是在偶數的位置(index是偶數)

def num_list(num):
    return [i for i in num if i %2 ==0 and num.index(i)%2==0]

num = [0,1,2,3,4,5,6,7,8,9,10]
result = num_list(num)
print(result)
複製代碼

54 使用單一的列表生成式來產生一個新的列表

該列表只包含知足如下條件的值,元素爲原始列表中偶數切片

list_data = [1,2,5,8,10,3,18,6,20]
res = [x for x in list_data[::2] if x %2 ==0]
print(res)
複製代碼

55 用一行代碼生成[1,4,9,16,25,36,49,64,81,100]

[x * x for x in range(1,11)]
複製代碼

56 輸入某年某月某日,判斷這一天是這一年的第幾天?

import datetime

y = int(input("請輸入4位數字的年份:"))
m = int(input("請輸入月份:"))
d = int(input("請輸入是哪一天"))

targetDay = datetime.date(y,m,d)
dayCount = targetDay - datetime.date(targetDay.year -1,12,31)
print("%s是 %s年的第%s天。"%(targetDay,y,dayCount.days))
複製代碼

57 兩個有序列表,l1,l2,對這兩個列表進行合併不可以使用extend

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]
    while len(l1)>0:
        tmp.append(l1[0])
        del l1[0]
    while len(l2)>0:
        tmp.append(l2[0])
        del l2[0]
    return tmp
複製代碼

58 給定一個任意長度數組,實現一個函數

讓全部奇數都在偶數前面,並且奇數升序排列,偶數降序排序,如字符串'1982376455',變成'1355798642'

# 方法一
def func1(l):
    if isinstance(l, str):
        l = [int(i) for i in l]
    l.sort(reverse=True)
    for i in range(len(l)):
        if l[i] % 2 > 0:
            l.insert(0, l.pop(i))
    print(''.join(str(e) for e in l))

# 方法二
def func2(l):
    print("".join(sorted(l, key=lambda x: int(x) % 2 == 0 and 20 - int(x) or int(x))))
複製代碼

59 寫一個函數找出一個整數數組中,第二大的數

def find_second_large_num(num_list):
    """ 找出數組第2大的數字 """
    # 方法一
    # 直接排序,輸出倒數第二個數便可
    tmp_list = sorted(num_list)
    print("方法一\nSecond_large_num is :", tmp_list[-2])
    
    # 方法二
    # 設置兩個標誌位一個存儲最大數一個存儲次大數
    # two 存儲次大值,one 存儲最大值,遍歷一次數組便可,先判斷是否大於 one,若大於將 one 的值給 two,將 num_list[i] 的值給 one,不然比較是否大於two,若大於直接將 num_list[i] 的值給two,不然pass
    one = num_list[0]
    two = num_list[0]
    for i in range(1, len(num_list)):
        if num_list[i] > one:
            two = one
            one = num_list[i]
        elif num_list[i] > two:
            two = num_list[i]
    print("方法二\nSecond_large_num is :", two)
    
    # 方法三
    # 用 reduce 與邏輯符號 (and, or)
    # 基本思路與方法二同樣,可是不須要用 if 進行判斷。
    from functools import reduce
    num = reduce(lambda ot, x: ot[1] < x and (ot[1], x) or ot[0] < x and (x, ot[1]) or ot, num_list, (0, 0))[0]
    print("方法三\nSecond_large_num is :", num)
    
    
if __name__ == '__main___':
    num_list = [34, 11, 23, 56, 78, 0, 9, 12, 3, 7, 5]
    find_second_large_num(num_list)
複製代碼

60 閱讀一下代碼他們的輸出結果是什麼?

def multi():
    return [lambda x : i*x for i in range(4)]
print([m(3) for m in multi()])
複製代碼

正確答案是[9,9,9,9],而不是[0,3,6,9]產生的緣由是Python的閉包的後期綁定致使的,這意味着在閉包中的變量是在內部函數被調用的時候被查找的,由於,最後函數被調用的時候,for循環已經完成, i 的值最後是3,所以每個返回值的i都是3,因此最後的結果是[9,9,9,9]

61 統計一段字符串中字符出現的次數

# 方法一
def count_str(str_data):
    """定義一個字符出現次數的函數"""
    dict_str = {} 
    for i in str_data:
        dict_str[i] = dict_str.get(i, 0) + 1
    return dict_str
dict_str = count_str("AAABBCCAC")
str_count_data = ""
for k, v in dict_str.items():
    str_count_data += k + str(v)
print(str_count_data)

# 方法二
from collections import Counter

print("".join(map(lambda x: x[0] + str(x[1]), Counter("AAABBCCAC").most_common())))
複製代碼

62 Python中類方法、類實例方法、靜態方法有何區別?

類方法: 是類對象的方法,在定義時須要在上方使用 @classmethod 進行裝飾,形參爲cls,表示類對象,類對象和實例對象均可調用

類實例方法: 是類實例化對象的方法,只有實例對象能夠調用,形參爲self,指代對象自己;

靜態方法: 是一個任意函數,在其上方使用 @staticmethod 進行裝飾,能夠用對象直接調用,靜態方法實際上跟該類沒有太大關係

63 遍歷一個object的全部屬性,並print每個屬性名?

class Car:
    def __init__(self,name,loss): # loss [價格,油耗,千米數]
        self.name = name
        self.loss = loss
    
    def getName(self):
        return self.name
    
    def getPrice(self):
        # 獲取汽車價格
        return self.loss[0]
    
    def getLoss(self):
        # 獲取汽車損耗值
        return self.loss[1] * self.loss[2]

Bmw = Car("寶馬",[60,9,500]) # 實例化一個寶馬車對象
print(getattr(Bmw,"name")) # 使用getattr()傳入對象名字,屬性值。
print(dir(Bmw)) # 獲Bmw全部的屬性和方法
複製代碼

64 寫一個類,並讓它儘量多的支持操做符?

class Array:
    __list = []
    
    def __init__(self):
        print "constructor"
    
    def __del__(self):
        print "destruct"
    
    def __str__(self):
        return "this self-defined array class"

    def __getitem__(self,key):
        return self.__list[key]
    
    def __len__(self):
        return len(self.__list)

    def Add(self,value):
        self.__list.append(value)
    
    def Remove(self,index):
        del self.__list[index]
    
    def DisplayItems(self):
        print "show all items---"
        for item in self.__list:
            print item
    
        
複製代碼

65 關於Python內存管理,下列說法錯誤的是 B

A,變量沒必要事先聲明 B,變量無須先建立和賦值而直接使用

C,變量無須指定類型 D,可使用del釋放資源

66 Python的內存管理機制及調優手段?

內存管理機制: 引用計數、垃圾回收、內存池

引用計數:引用計數是一種很是高效的內存管理手段,當一個Python對象被引用時其引用計數增長1,

當其再也不被一個變量引用時則計數減1,當引用計數等於0時對象被刪除。弱引用不會增長引用計數

垃圾回收:

1.引用計數

引用計數也是一種垃圾收集機制,並且也是一種最直觀、最簡單的垃圾收集技術。當Python的某個對象的引用計數降爲0時,說明沒有任何引用指向該對象,該對象就成爲要被回收的垃圾了。好比某個新建對象,它被分配給某個引用,對象的引用計數變爲1,若是引用被刪除,對象的引用計數爲0,那麼該對象就能夠被垃圾回收。不過若是出現循環引用的話,引用計數機制就再也不起有效的做用了。

2.標記清除

調優手段

1.手動垃圾回收

2.調高垃圾回收閾值

3.避免循環引用

67 內存泄露是什麼?如何避免?

內存泄漏指因爲疏忽或錯誤形成程序未能釋放已經再也不使用的內存。內存泄漏並不是指內存在物理上的消失,而是應用程序分配某段內存後,因爲設計錯誤,致使在釋放該段內存以前就失去了對該段內存的控制,從而形成了內存的浪費。

__del__()函數的對象間的循環引用是致使內存泄露的主兇。不使用一個對象時使用: del object 來刪除一個對象的引用計數就能夠有效防止內存泄露問題。

經過Python擴展模塊gc 來查看不能回收的對象的詳細信息。

能夠經過 sys.getrefcount(obj) 來獲取對象的引用計數,並根據返回值是否爲0來判斷是否內存泄露

68 python常見的列表推導式?

[表達式 for 變量 in 列表] 或者 [表達式 for 變量 in 列表 if 條件]

69 簡述read、readline、readlines的區別?

read 讀取整個文件

readline 讀取下一行

readlines 讀取整個文件到一個迭代器以供咱們遍歷

70 什麼是Hash(散列函數)?

散列函數(英語:Hash function)又稱散列算法哈希函數,是一種從任何一種數據中建立小的數字「指紋」的方法。散列函數把消息或數據壓縮成摘要,使得數據量變小,將數據的格式固定下來。該函數將數據打亂混合,從新建立一個叫作散列值(hash values,hash codes,hash sums,或hashes)的指紋。散列值一般用一個短的隨機字母和數字組成的字符串來表明

71 python函數重載機制?

函數重載主要是爲了解決兩個問題。 1。可變參數類型。 2。可變參數個數。

另外,一個基本的設計原則是,僅僅當兩個函數除了參數類型和參數個數不一樣之外,其功能是徹底相同的,此時才使用函數重載,若是兩個函數的功能其實不一樣,那麼不該當使用重載,而應當使用一個名字不一樣的函數。

好吧,那麼對於狀況 1 ,函數功能相同,可是參數類型不一樣,python 如何處理?答案是根本不須要處理,由於 python 能夠接受任何類型的參數,若是函數的功能相同,那麼不一樣的參數類型在 python 中極可能是相同的代碼,沒有必要作成兩個不一樣函數。

那麼對於狀況 2 ,函數功能相同,但參數個數不一樣,python 如何處理?你們知道,答案就是缺省參數。對那些缺乏的參數設定爲缺省參數便可解決問題。由於你假設函數功能相同,那麼那些缺乏的參數終歸是須要用的。

好了,鑑於狀況 1 跟 狀況 2 都有了解決方案,python 天然就不須要函數重載了。

72 手寫一個判斷時間的裝飾器

import datetime


class TimeException(Exception):
    def __init__(self, exception_info):
        super().__init__()
        self.info = exception_info

    def __str__(self):
        return self.info


def timecheck(func):
    def wrapper(*args, **kwargs):
        if datetime.datetime.now().year == 2019:
            func(*args, **kwargs)
        else:
            raise TimeException("函數已過期")

    return wrapper


@timecheck
def test(name):
    print("Hello {}, 2019 Happy".format(name))


if __name__ == "__main__":
    test("backbp")
複製代碼

73 使用Python內置的filter()方法來過濾?

list(filter(lambda x: x % 2 == 0, range(10)))
複製代碼

74 編寫函數的4個原則

1.函數設計要儘可能短小

2.函數聲明要作到合理、簡單、易於使用

3.函數參數設計應該考慮向下兼容

4.一個函數只作一件事情,儘可能保證函數語句粒度的一致性

75 函數調用參數的傳遞方式是值傳遞仍是引用傳遞?

Python的參數傳遞有:位置參數、默認參數、可變參數、關鍵字參數。

函數的傳值究竟是值傳遞仍是引用傳遞、要分狀況:

不可變參數用值傳遞:像整數和字符串這樣的不可變對象,是經過拷貝進行傳遞的,由於你不管如何都不可能在原處改變不可變對象。

可變參數是引用傳遞:好比像列表,字典這樣的對象是經過引用傳遞、和C語言裏面的用指針傳遞數組很類似,可變對象能在函數內部改變。

76 如何在function裏面設置一個全局變量

globals() # 返回包含當前做用餘全局變量的字典。
global 變量 設置使用全局變量
複製代碼

77 對缺省參數的理解 ?

缺省參數指在調用函數的時候沒有傳入參數的狀況下,調用默認的參數,在調用函數的同時賦值時,所傳入的參數會替代默認參數。

*args是不定長參數,它能夠表示輸入參數是不肯定的,能夠是任意多個。

**kwargs是關鍵字參數,賦值的時候是以鍵值對的方式,參數能夠是任意多對在定義函數的時候

不肯定會有多少參數會傳入時,就可使用兩個參數

78 帶參數的裝飾器?

帶定長參數的裝飾器

def new_func(func):
    def wrappedfun(username, passwd):
        if username == 'root' and passwd == '123456789':
            print('經過認證')
            print('開始執行附加功能')
            return func()
       	else:
            print('用戶名或密碼錯誤')
            return
    return wrappedfun

@new_func
def origin():
    print('開始執行函數')
origin('root','123456789')
複製代碼

帶不定長參數的裝飾器

def new_func(func):
    def wrappedfun(*parts):
        if parts:
            counts = len(parts)
            print('本系統包含 ', end='')
            for part in parts:
                print(part, ' ',end='')
            print('等', counts, '部分')
            return func()
        else:
            print('用戶名或密碼錯誤')
            return func()
   return wrappedfun

複製代碼

79 爲何函數名字能夠當作參數用?

Python中一切皆對象,函數名是函數在內存中的空間,也是一個對象

80 Python中pass語句的做用是什麼?

在編寫代碼時只寫框架思路,具體實現還未編寫就能夠用pass進行佔位,是程序不報錯,不會進行任何操做。

81 有這樣一段代碼,print c會輸出什麼,爲何?

a = 10
b = 20
c = [a]
a = 15
複製代碼

答:10對於字符串,數字,傳遞是相應的值

82 交換兩個變量的值?

a, b = b, a
複製代碼

83 map函數和reduce函數?

map(lambda x: x * x, [1, 2, 3, 4])   # 使用 lambda
# [1, 4, 9, 16]
reduce(lambda x, y: x * y, [1, 2, 3, 4])  # 至關於 ((1 * 2) * 3) * 4
# 24
複製代碼

84 回調函數,如何通訊的?

回調函數是把函數的指針(地址)做爲參數傳遞給另外一個函數,將整個函數看成一個對象,賦值給調用的函數。

85 Python主要的內置數據類型都有哪些? print dir( ‘a ’) 的輸出?

內建類型:布爾類型,數字,字符串,列表,元組,字典,集合

輸出字符串'a'的內建方法

86 map(lambda x:xx,[y for y in range(3)])的輸出?

[0, 1, 4]
複製代碼

87 hasattr() getattr() setattr() 函數使用詳解?

hasattr(object,name)函數:

判斷一個對象裏面是否有name屬性或者name方法,返回bool值,有name屬性(方法)返回True,不然返回False。

class function_demo(object):
    name = 'demo'
    def run(self):
        return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "name") # 判斷對象是否有name屬性,True
res = hasattr(functiondemo, "run") # 判斷對象是否有run方法,True
res = hasattr(functiondemo, "age") # 判斷對象是否有age屬性,False
print(res)
複製代碼

getattr(object, name[,default])函數:

獲取對象object的屬性或者方法,若是存在則打印出來,若是不存在,打印默認值,默認值可選。注意:若是返回的是對象的方法,則打印結果是:方法的內存地址,若是須要運行這個方法,能夠在後面添加括號().

functiondemo = function_demo()
getattr(functiondemo, "name")# 獲取name屬性,存在就打印出來 --- demo
getattr(functiondemo, "run") # 獲取run 方法,存在打印出方法的內存地址
getattr(functiondemo, "age") # 獲取不存在的屬性,報錯
getattr(functiondemo, "age", 18)# 獲取不存在的屬性,返回一個默認值
複製代碼

setattr(object, name, values)函數:

給對象的屬性賦值,若屬性不存在,先建立再賦值

class function_demo(object):
    name = "demo"
    def run(self):
        return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "age") # 判斷age屬性是否存在,False
print(res)
setattr(functiondemo, "age", 18) # 對age屬性進行賦值,無返回值
res1 = hasattr(functiondemo, "age") # 再次判斷屬性是否存在,True
複製代碼

綜合使用

class function_demo(object):
    name = "demo"
    def run(self):
        return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "addr") # 先判斷是否存在
if res:
    addr = getattr(functiondemo, "addr")
    print(addr)
else:
    addr = getattr(functiondemo, "addr", setattr(functiondemo, "addr", "北京首都"))
    print(addr)
複製代碼

88 一句話解決階乘函數?

reduce(lambda x,y : x*y,range(1,n+1))
複製代碼

89 對設計模式的理解,簡述你瞭解的設計模式?

設計模式是通過總結,優化的,對咱們常常會碰到的一些編程問題的可重用解決方案。一個設計模式並不像一個類或一個庫那樣可以直接做用於咱們的代碼,反之,設計模式更爲高級,它是一種必須在特定情形下實現的一種方法模板。 常見的是工廠模式和單例模式

90 請手寫一個單例

#python2
class A(object):
    __instance = None
    def __new__(cls,*args,**kwargs):
        if cls.__instance is None:
            cls.__instance = objecet.__new__(cls)
            return cls.__instance
        else:
            return cls.__instance
複製代碼

91 單例模式的應用場景有那些?

單例模式應用的場景通常發如今如下條件下: 資源共享的狀況下,避免因爲資源操做時致使的性能或損耗等,如日誌文件,應用配置。 控制資源的狀況下,方便資源之間的互相通訊。如線程池等,1,網站的計數器 2,應用配置 3.多線程池 4數據庫配置 數據庫鏈接池 5.應用程序的日誌應用...

92 用一行代碼生成[1,4,9,16,25,36,49,64,81,100]

print([x*x for x in range(1, 11)])
複製代碼

93 對裝飾器的理解,並寫出一個計時器記錄方法執行性能的裝飾器?

裝飾器本質上是一個callable object ,它可讓其餘函數在不須要作任何代碼變更的前提下增長額外功能,裝飾器的返回值也是一個函數對象。

import time
from functools import wraps

def timeit(func):
 @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.clock()
        ret = func(*args, **kwargs)
        end = time.clock()
        print('used:',end-start)
        return ret
    
    return wrapper
@timeit
def foo():
    print('in foo()'foo())
複製代碼

94 解釋如下什麼是閉包?

在函數內部再定義一個函數,而且這個函數用到了外邊函數的變量,那麼將這個函數以及用到的一些變量稱之爲閉包。

95 函數裝飾器有什麼做用?

裝飾器本質上是一個callable object,它能夠在讓其餘函數在不須要作任何代碼的變更的前提下增長額外的功能。裝飾器的返回值也是一個函數的對象,它常常用於有切面需求的場景。好比:插入日誌,性能測試,事務處理,緩存。權限的校驗等場景,有了裝飾器就能夠抽離出大量的與函數功能自己無關的雷同代碼併發並繼續使用。 詳細參考:manjusaka.itscoder.com/2018/02/23/…

96 生成器,迭代器的區別?

迭代器是遵循迭代協議的對象。用戶可使用 iter() 以從任何序列獲得迭代器(如 list, tuple, dictionary, set 等)。另外一個方法則是建立一個另外一種形式的迭代器 —— generator 。要獲取下一個元素,則使用成員函數 next()(Python 2)或函數 next() function (Python 3) 。當沒有元素時,則引起 StopIteration 此例外。若要實現本身的迭代器,則只要實現 next()(Python 2)或 __next__()( Python 3)

生成器(Generator),只是在須要返回數據的時候使用yield語句。每次next()被調用時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和全部的數據值)

區別: 生成器能作到迭代器能作的全部事,並且由於自動建立iter()和next()方法,生成器顯得特別簡潔,並且生成器也是高效的,使用生成器表達式取代列表解析能夠同時節省內存。除了建立和保存程序狀態的自動方法,當發生器終結時,還會自動拋出StopIteration異常。

97 X是什麼類型?

X= (i for i in range(10)) X是 generator類型

98 請用一行代碼 實現將1-N 的整數列表以3爲單位分組

N =100
print ([[x for x in range(1,100)] [i:i+3] for i in range(0,100,3)])
複製代碼

99 Python中yield的用法?

yield就是保存當前程序執行狀態。你用for循環的時候,每次取一個元素的時候就會計算一次。用yield的函數叫generator,和iterator同樣,它的好處是不用一次計算全部元素,而是用一次算一次,能夠節省不少空間,generator每次計算須要上一次計算結果,因此用yield,不然一return,上次計算結果就沒了

相關文章
相關標籤/搜索