1. 程式人生 > >Python基礎知識點總結

Python基礎知識點總結

   學了一年多的Python,去年做了一段時間的爬蟲專案,近來在做資料分析和機器學習的東西,抽空整理一下以前學的Python基礎知識點,有借鑑與總結。具體知識點後續會分段展開深入。

1.到底什麼是Python?你可以在回答中與其他技術進行對比(據說是某面試題)。

答案:下面是一些關鍵點:

l Python是一種解釋型語言。這就是說,與C語言和C的衍生語言不同,Python程式碼在執行之前不需要編譯。其他解釋型語言還包括PHP和Ruby。

l Python是動態型別語言,指的是你在宣告變數時,不需要說明變數的型別。你可以直接編寫類似x=111和x="I'm a string"這樣的程式碼,程式不會報錯。

l Python非常適合面向物件的程式設計(OOP),因為它支援通過組合(composition)與繼承(inheritance)的方式定義類(class)。Python中沒有訪問說明符(access specifier,類似C++中的public和private),這麼設計的依據是“大家都是成年人了”。

l 在Python語言中,函式是第一類物件(firstclassobjects)。這指的是它們可以被指定給變數,函式既能返回函式型別,也可以接受函式作為輸入。類(class)也是第一類物件。

l Python程式碼編寫快,但是執行速度比編譯語言通常要慢。好在Python允許加入基於C語言編寫的擴充套件,因此我們能夠優化程式碼,消除瓶頸,這點通常是可以實現的。numpy就是一個很好地例子,它的執行速度真的非常快,因為很多算術運算其實並不是通過Python實現的。

l Python用途非常廣泛——網路應用,自動化,科學建模,大資料應用,等等。它也常被用作“膠水語言”,幫助其他語言和元件改善執行狀況。

l Python讓困難的事情變得容易,因此程式設計師可以專注於演算法和資料結構的設計,而不用處理底層的細節。

2.這兩個引數是什麼意思:*args,**kwargs?我們為什麼要使用它們?

答案:如果我們不確定要往函式中傳入多少個引數,或者我們想往函式中以列表和元組的形式傳引數時,那就使要用*args;如果我們不知道要往函式中傳入多少個關鍵詞引數,或者想傳入字典的值作為關鍵詞引數時,那就要使用**kwargs。args和kwargs這兩個識別符號是約定俗成的用法,你當然還可以用*bob和**billy,但是這樣就並不太妥。

3.簡要描述Python的垃圾回收機制(garbage collection)。

答案:這裡能說的很多。你應該提到下面幾個主要的點:

l Python在記憶體中儲存了每個物件的引用計數(reference count)。如果計數值變成0,那麼相應的物件就會小時,分配給該物件的記憶體就會釋放出來用作他用。

l 偶爾也會出現引用迴圈(reference cycle)。垃圾回收器會定時尋找這個迴圈,並將其回收。舉個例子,假設有兩個物件o1和o2,而且符合o1.x == o2和o2.x == o1這兩個條件。如果o1和o2沒有其他程式碼引用,那麼它們就不應該繼續存在。但它們的引用計數都是1。

l Python中使用了某些啟發式演算法(heuristics)來加速垃圾回收。例如,越晚建立的物件更有可能被回收。物件被建立之後,垃圾回收器會分配它們所屬的代(generation)。每個物件都會被分配一個代,而被分配更年輕代的物件是優先被處理的。

4.|說說你對zen of python的理解,你有什麼辦法看到它?

答案:Python之禪,Python秉承一種獨特的簡潔和可讀行高的語法,以及高度一致的程式設計模

式,符合“大腦思維習慣”,使Python易於學習、理解和記憶。Python同時採用了一條

極簡主義的設計理念,瞭解完整的Python哲學理念,可以在任何一個Python互動直譯器

中鍵入import this命令,這是Python隱藏的一個彩蛋:描繪了一系列Python設計原則。

如今已是Python社群內流行的行話"EIBTI",明瞭勝於晦澀這條規則的簡稱. 在Python

的思維方式中,明瞭勝於晦澀,簡潔勝於複雜。

5.是否遇到過python的模組間迴圈引用的問題,如何避免它?

答案:這是程式碼結構設計的問題,模組依賴和類依賴

如果老是覺得碰到迴圈引用,很可能是模組的分界線劃錯地方了。可能是把應該在一起的東西硬拆開了,可能是某些職責放錯地方了,可能是應該抽象的東西沒抽象

總之微觀程式碼規範可能並不能幫到太多,重要的是更巨集觀的劃分模組的經驗技巧,推薦uml,腦圖,白板等等圖形化的工具先梳理清楚整個系統的總體結構和職責分工採取辦法,從設計模式上來規避這個問題,比如:

1. 使用 “__all__”白名單開放介面

2. 儘量避免 import

6.有用過with statement嗎?它的好處是什麼?

with open('text.txt') as myfile:

... while True:

... line = myfile.readline()

... if not line:

... break

... print line,

#with語句使用所謂的上下文管理器對程式碼塊進行包裝,允許上下文管理器實現一些設定和清理操作。

# 例如:檔案可以作為上下文管理器使用,它們可以關閉自身作為清理的一部分。

# NOTE:在PYTHON2.5中,需要使用from __future__ import with_statement進行with語句的匯入

7.Python裡面search()和match()的區別

>>> import re

>>> re.match(r'python','Programing Python, should be pythonic')

>>> obj1 = re.match(r'python','Programing Python, should be pythonic') #返回None

>>> obj2 = re.search(r'python','Programing Python, should be pythonic') #找到pythonic

>>> obj2.group()

'python'

#re.match只匹配字串的開始,如果字串開始不符合正則表示式,則匹配失敗,函式返回None;#re.search匹配整個字串,直到找到一個匹配。

8.Python程式中文輸出問題怎麼解決

在Python3中,對中文進行了全面的支援,但在Python2.x中需要進行相關的設定才能使用中文。否則會出現亂碼。

Python預設採取的ASCII編碼,字母、標點和其他字元只使用一個位元組來表示,但對於中文字元來說,一個位元組滿足不了需

求。為了能在計算機中表示所有的中文字元,中文編碼採用兩個位元組表示。如果中文編碼和ASCII混合使用的話,就會導致解碼錯誤,從而才生亂碼。

解決辦法:

互動式命令中:一般不會出現亂碼,無需做處理

py指令碼檔案中:跨字符集必須做設定,否則亂碼

1. 首先在開頭一句新增:

# coding = utf‐8

# 或

# coding = UTF‐8

# 或

# ‐*‐ coding: utf‐8 ‐*‐

2. 其次需將檔案儲存為UTF‐8的格式!

3. 最後: s.decode('utf‐8').encode('gbk')

9.什麼是lambda函式

函式使用:

1. 程式碼塊重複,這時候必須考慮到函式,降低程式的冗餘度

2. 程式碼塊複雜,這時候必須考慮到函式,降低程式的複雜度

Python有兩種函式,一種是def定義,一種是lambda函式()

當程式程式碼很短,且該函式只使用一次,為了程式的簡潔,及節省變數記憶體佔用空間,引入了匿名函式這個概念

>>> nums = range(2,20)

>>> for i in nums:

nums = filter(lambda x:x==i or x % i,nums)

>>> nums

[2, 3, 5, 7, 11, 13, 17, 19]

10.Python裡面如何拷貝一個物件

切片S[:] # 注不能應用於字典

深淺寶貝 # 能應用於所有序列和字典

1. 淺拷貝D.copy()方法

2. 深拷貝deepcopy(D)方法

11.Python中pass語句的作用是什麼

pass語句什麼也不做,一般作為佔位符或者建立佔位程式

12.Python是如何進行記憶體管理的

python內部使用引用計數,來保持追蹤記憶體中的物件,Python內部記錄了物件有多少個引用,即引用計數,當物件被建立時就建立了一個引用計數,當物件不再需要時,這個物件的引用計數為0時,它被垃圾回收。所有這些都是自動完成,不需要像C一樣,人工干預,從而提高了程式設計師的效率和程式的健壯性。

13.Python異常處理介紹一下

程式中出現異常情況時就需要異常處理。比如當你開啟一個不存在的檔案時。當你的程式中有一些無效的語句時,Python會提示你有錯誤存在。下面是一個拼寫錯誤的例子,print寫成了Print

下面是異常最常見的幾種角色

1. 錯誤處理

>>>可以在程式程式碼中捕捉和相應錯誤,或者忽略已發生的異常。

>>>如果忽略錯誤,PYTHON預設的異常處理行為將啟動:停止程式,列印錯誤資訊。

>>>如果不想啟動這種預設行為,就用try語句來捕捉異常並從異常中恢復。

2. 事件通知

>>>異常也可用於發出有效狀態的訊號,而不需在程式間傳遞結果標誌位。或者刻意對其進行測試

3. 特殊情況處理

>>>有時,發生了某種很罕見的情況,很難調整程式碼區處理。通常會在異常處理中處理,從而省去應對特殊情況的程式碼

4. 終止行為

>>>try/finally語句可確保一定會進行需要的結束運算,無論程式是否有異常

5. 非常規控制流程

14.介紹一下Python中的filter方法

filter就像map,reduce,apply,zip等都是內建函式,用C語言實現,具有速度快,功能強大等

優點。

用於過濾與函式func()不匹配的值, 類似於SQL中select value != 'a'

相當於一個迭代器,呼叫一個布林函式func來迭代seq中的每個元素,返回一個是bool_seq返

回為True的序列

>>>第一個引數: function or None, 函式或None

>>>第二個引數: sequence,序列

15.介紹一下except的用法和作用

try/except: 捕捉由PYTHON自身或寫程式過程中引發的異常並恢復

except: 捕捉所有其他異常

except name: 只捕捉特定的異常

except name, value: 捕捉異常及格外的資料(例項)

except (name1,name2) 捕捉列出來的異常

except (name1,name2),value: 捕捉任何列出的異常,並取得額外資料

else: 如果沒有引發異常就執行

finally: 總是會執行此處程式碼

16.inspect模組有什麼用

inspect模組提供了一系列函式用於幫助使用自省。

檢查物件型別

is{module|class|function|method|builtin}(obj): 檢查物件是否為模組、類、函式、方法、內建函式或方法。

isroutine(obj): 用於檢查物件是否為函式、方法、內建函式或方法等等可呼叫型別。

獲取物件資訊

getmembers(object[, predicate]): 這個方法是dir()的擴充套件版,它會將dir()找到的名字對應的屬性一併返回。

getmodule(object): 它返回object的定義所在的模組物件。

get{file|sourcefile}(object): 獲取object的定義所在的模組的檔名|原始碼檔名(如果沒有則返回None)。

get{source|sourcelines}(object): 獲取object的定義的原始碼,以字串|字串列表返回。

getargspec(func): 僅用於方法,獲取方法宣告的引數,返回元組,分別是(普通引數名的列表, *引數名, **引數名, 預設值元組)。

17.Python列表與元組的區別是什麼?分別在什麼情況下使用?

Python中列表和元組是序列,因此都能進行新增,刪除,更新,切片等操作。但列表是可變物件,元祖是不可變物件。

元祖主要用於函式賦值,字串格式化等。但列表中的方法更多些,也是PYTHON中更常用的資料結構。

18.解釋一下python的and-or語法

0 and *不需要再考慮*是0還是1,結果是0

1 and *需要考慮*是0還是1來決定結果。

1 or *不需要考慮後面的*,結果為1

0 or *需要考慮後面的*來決定結果 這個語法看起來類似於 C 語言中的 bool ? a : b 表示式。整個表示式從左到右進行演算,所以先進行 and 表示式的演算。

1 and 'first' 演算值為 'first',然後 'first' or 'second' 的演算值為 'first'。

0 and 'first' 演算值為False,然後 0 or 'second' 演算值為 'second'。

and‐or主要是用來模仿三目運算子 bool?a:b的,即當表示式bool為真,則取a否則取b。

and‐or 技巧,bool and a or b 表示式,當a 在布林上下文中的值為假時,不會像 C 語言表示式 bool ? a : b 那樣工作。

19.在Python中, list, tuple, dict, set有什麼區別, 主要應用在什麼樣的場景?

解答:定義list: 連結串列, 有序的專案, 通過索引進行查詢, 使用方括號"[]";

tuple: 元組, 元組將多樣的物件集合到一起, 不能修改, 通過索引進行查詢, 使用括號"()";

dict: 字典, 字典是一組鍵(key)和值(value)的組合, 通過鍵(key)進行查詢, 沒有順序, 使用大括號"{}";

set: 集合,無序, 元素只出現一次, 自動去重, 使用"set([])";

應用場景: 

list, 簡單的資料集合, 可以使用索引; 

tuple, 把一些資料當做一個整體去使用, 不能修改;

dict, 使用鍵值和值進行關聯的資料;

set, 資料只出現一次, 只關心資料是否出現, 不關心其位置;

程式碼:

mylist = [1, 2, 3, 4, 'Oh']  

mytuple = (1, 2, 'Hello', (4, 5))  

mydict = {'Wang' : 1, 'Hu' : 2, 'Liu' : 4}  

myset = set(['Wang', 'Hu', 'Liu', 4, 'Wang'])

20. 靜態函式, 類函式, 成員函式的區別?

解答:

定義:

靜態函式(@staticmethod): 即靜態方法,主要處理與這個類的邏輯關聯;

類函式(@classmethod): 即類方法, 更關注於從類中呼叫方法, 而不是在例項中呼叫方法, 可以用作方法過載, 傳入引數cls;

成員函式: 例項的方法, 只能通過例項進行呼叫;

具體應用:

日期的方法, 可以通過例項化(__init__)進行資料輸出, 傳入引數self;

可以通過類的方法(@classmethod)進行資料轉換, 傳入引數cls;

可以通過靜態方法(@staticmethod)進行資料驗證;

程式碼:

# -*- coding: utf-8 -*-  

#eclipse pydev, python 3.3  

#by C.L.Wang  

class Date(object):  

    day = 0  

    month = 0  

    year = 0  

    def __init__(self, day=0, month=0, year=0):  

        self.day = day  

        self.month = month  

        self.year = year  

    def display(self):  

        return "{0}*{1}*{2}".format(self.day, self.month, self.year)  

    @classmethod  

    def from_string(cls, date_as_string):  

        day, month, year = map(int, date_as_string.split('-'))  

        date1 = cls(day, month, year)  

        return date1  

    @staticmethod  

    def is_date_valid(date_as_string):  

        day, month, year = map(int, date_as_string.split('-'))  

        return day <= 31 and month <= 12 and year <= 3999  

date1 = Date('12', '11', '2014')  

date2 = Date.from_string('11-13-2014')  

print(date1.display())  

print(date2.display())  

print(date2.is_date_valid('11-13-2014'))  

print(Date.is_date_valid('11-13-2014'))

21. a=1, b=2, 不用中間變數交換a和b的值

解答:

兩種形式: 加法或異或

程式碼:

a = 1  

b = 2  

a = a + b  

b = a - b  

a = a - b  

print ('a = {0}, b = {1}'.format(a, b))  

a = a ^ b  

b = a ^ b  

a = a ^ b  

print ('a = {0}, b = {1}'.format(a, b))

22. 寫一個函式, 輸入一個字串, 返回倒序排列的結果: 如: string_reverse(‘abcdef’), 返回: ‘fedcba’(請採用多種方法實現, 並對實現方法進行比較)

解答:

5種方法的比較:

1. 簡單的步長為-1, 即字串的翻轉;

2. 交換前後字母的位置;

3. 遞迴的方式, 每次輸出一個字元;

4. 雙端佇列, 使用extendleft()函式;

5. 使用for迴圈, 從左至右輸出;

程式碼:

string = 'abcdef'  

def string_reverse1(string):  

    return string[::-1]  

def string_reverse2(string):  

    t = list(string)  

    l = len(t)  

    for i,j in zip(range(l-1, 0, -1), range(l//2)):  

        t[i], t[j] = t[j], t[i]  

    return "".join(t)  

def string_reverse3(string):  

    if len(string) <= 1:  

        return string  

    return string_reverse3(string[1:]) + string[0]  

from collections import deque  

def string_reverse4(string):  

    d = deque()  

    d.extendleft(string)  

    return ''.join(d)  

def string_reverse5(string):  

    #return ''.join(string[len(string) - i] for i in range(1, len(string)+1))  

    return ''.join(string[i] for i in range(len(string)-1, -1, -1))  

print(string_reverse1(string))  

print(string_reverse2(string))  

print(string_reverse3(string))  

print(string_reverse4(string))  

print(string_reverse5(string))

23.介紹一下python的異常處理機制

解答:Python的異常處理機制:

try: 嘗試丟擲異常;

raise: 引發異常;

except: 處理異常;

finally: 是否發生異常都需要做的事情;

建立新的異常型別, 需要繼承Exception類, 可以定義類的屬性, 便於處理異常;

開發體會:

異常主要處理讀取檔案, 也可以使用with的方法讀取檔案; 還可以用於網路連線, 異常可以包含大量的錯誤資訊, 進行錯誤處理.

程式碼:

class ShortInputException(Exception):  

    def __init__(self, length, atleast):  

        Exception.__init__(self)  

        self.length = length  

        self.atleast = atleast  

while True:  

    try:  

        text = raw_input('Enter somthing-->')  

        if len(text) < 3:  

            raise ShortInputException(len(text), 3)  

    except EOFError:  

        print('Why did you do an EOF on me')  

    except ShortInputException as ex:  

        print('ShortInputException The input was {0} long, \  

excepted at least {1}. '.format(ex.length, ex.atleast))  

    else:  

        print('No exception was raised. ')  

    finally:  

        print('Over')

24.Python自省

這個也是python彪悍的特性.自省就是面向物件的語言所寫的程式在執行時,所能知道物件的型別.簡單一句就是執行時能夠獲得物件的型別.比如type(),dir(),getattr(),hasattr(),isinstance().

25.Python中過載

函式過載主要是為了解決兩個問題。

l 可變引數型別。

l 可變引數個數。

另外,一個基本的設計原則是,僅僅當兩個函式除了引數型別和引數個數不同以外,其功能是完全相同的,此時才使用函式過載,如果兩個函式的功能其實不同,那麼不應當使用過載,而應當使用一個名字不同的函式。

好吧,那麼對於情況 1 ,函式功能相同,但是引數型別不同,python 如何處理?答案是根本不需要處理,因為python 可以接受任何型別的引數,如果函式的功能相同,那麼不同的引數型別在 python 中很可能是相同的程式碼,沒有必要做成兩個不同函式。

那麼對於情況 2 ,函式功能相同,但引數個數不同,python 如何處理?大家知道,答案就是預設引數。對那些缺少的引數設定為預設引數即可解決問題。因為你假設函式功能相同,那麼那些缺少的引數終歸是需要用的。

好了,鑑於情況 1 跟 情況 2 都有了解決方案,python 自然就不需要函式過載了。

26.__new__和__init__的區別

這個__new__確實很少見到,先做了解吧.

l __new__是一個靜態方法,而__init__是一個例項方法.

l __new__方法會返回一個建立的例項,而__init__什麼都不返回.

l 只有在__new__返回一個cls的例項時後面的__init__才能被呼叫.

l 當建立一個新例項時呼叫__new__,初始化一個例項時用__init__.

ps: __metaclass__是建立類時起作用.所以我們可以分別使用__metaclass__,__new__和__init__來分別在類建立,例項建立和例項初始化的時候做一些小手腳.


27.GIL執行緒全域性鎖

執行緒全域性鎖(Global Interpreter Lock),即Python為了保證執行緒安全而採取的獨立執行緒執行的限制,說白了就是一個核只能在同一時間執行一個執行緒.

解決辦法就是多程序和下面的協程(協程也只是單CPU,但是能減小切換代價提升效能).

28.協程

簡單點說協程是程序和執行緒的升級版,程序和執行緒都面臨著核心態和使用者態的切換問題而耗費許多切換時間,而協程就是使用者自己控制切換的時機,不再需要陷入系統的核心態.

Python裡最常見的yield就是協程的思想!可以檢視第九個問題.

29.閉包

閉包(closure)是函數語言程式設計的重要的語法結構。閉包也是一種組織程式碼的結構,它同樣提高了程式碼的可重複使用性。

當一個內嵌函式引用其外部作作用域的變數,我們就會得到一個閉包. 總結一下,建立一個閉包必須滿足以下幾點:

l 必須有一個內嵌函式

l 內嵌函式必須引用外部函式中的變數

l 外部函式的返回值必須是內嵌函式

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

重點是函式執行後並不會被撤銷,就像16題的instance字典一樣,當函式執行完後,instance並不被銷燬,而是繼續留在記憶體空間裡.這個功能類似類裡的類變數,只不過遷移到了函式上.

閉包就像個空心球一樣,你知道外面和裡面,但你不知道中間是什麼樣.

30.Python垃圾回收機制

Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,通過“標記-清除”(mark and sweep)解決容器物件可能產生的迴圈引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。

1 引用計數

PyObject是每個物件必有的內容,其中ob_refcnt就是做為引用計數。當一個物件有新的引用時,它的ob_refcnt就會增加,當引用它的物件被刪除,它的ob_refcnt就會減少.引用計數為0時,該物件生命就結束了。

優點:

簡單

實時性

缺點:

維護引用計數消耗資源

迴圈引用

2 標記-清除機制

基本思路是先按需分配,等到沒有空閒記憶體的時候從暫存器和程式棧上的引用出發,遍歷以物件為節點、以引用為邊構成的圖,把所有可以訪問到的物件打上標記,然後清掃一遍記憶體空間,把所有沒標記的物件釋放。

3 分代技術

分代回收的整體思想是:將系統中的所有記憶體塊根據其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率隨著“代”的存活時間的增大而減小,存活時間通常利用經過幾次垃圾回收來度量。

Python預設定義了三代物件集合,索引數越大,物件存活時間越長。

舉例:
當某些記憶體塊M經過了3次垃圾收集的清洗之後還存活時,我們就將記憶體塊M劃到一個集合A中去,而新分配的記憶體都劃分到集合B中去。當垃圾收集開始工作時,大多數情況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔相當長一段時間後才進行,這就使得垃圾收集機制需要處理的記憶體少了,效率自然就提高了。在這個過程中,集合B中的某些記憶體塊由於存活時間長而會被轉移到集合A中,當然,集合A中實際上也存在一些垃圾,這些垃圾的回收會因為這種分代的機制而被延遲。

31.read,readline和readlines

l  read 讀取整個檔案

l  readline 讀取下一行,使用生成器方法

l  readlines 讀取整個檔案到一個迭代器以供我們遍歷

32.簡述函數語言程式設計

在函數語言程式設計中,函式是基本單位,變數只是一個名稱,而不是一個儲存單元。除了匿名函式外,Python還使用fliter(),map(),reduce(),apply()函式來支援函數語言程式設計。

33.什麼是匿名函式,匿名函式有什麼侷限性

匿名函式,也就是lambda函式,通常用在函式體比較簡單的函式上。匿名函式顧名思義就是函式沒有名字,因此不用擔心函式名衝突。不過Python對匿名函式的支援有限,只有一些簡單的情況下可以使用匿名函式。

34.如何捕獲異常,常用的異常機制有哪些?

如果我們沒有對異常進行任何預防,那麼在程式執行的過程中發生異常,就會中斷程式,呼叫python預設的異常處理器,並在終端輸出異常資訊。

try…except…finally語句:當try語句執行時發生異常,回到try語句層,尋找後面是否有except語句。找到except語句後,會呼叫這個自定義的異常處理器。except將異常處理完畢後,程式繼續往下執行。finally語句表示,無論異常發生與否,finally中的語句都要執行。

assert語句:判斷assert後面緊跟的語句是True還是False,如果是True則繼續執行print,如果是False則中斷程式,呼叫預設的異常處理器,同時輸出assert語句逗號後面的提示資訊。

with語句:如果with語句或語句塊中發生異常,會呼叫預設的異常處理器處理,但檔案還是會正常關閉。

35.copy()與deepcopy()的區別

copy是淺拷貝,只拷貝可變物件的父級元素。 deepcopy是深拷貝,遞迴拷貝可變物件的所有元素。

36.函式裝飾器有什麼作用

裝飾器本質上是一個Python函式,它可以讓其他函式在不需要做任何程式碼變動的前提下增加額外功能,裝飾器的返回值也是一個函式物件。它經常用於有切面需求的場景,比如:**日誌、效能測試、事務處理、快取、許可權校驗等場景。有了裝飾器,就可以抽離出大量與函式功能本身無關的雷同程式碼並繼續重用。

37.簡述Python的作用域以及Python搜尋變數的順序

Python作用域簡單說就是一個變數的名稱空間。程式碼中變數被賦值的位置,就決定了哪些範圍的物件可以訪問這個變數,這個範圍就是變數的作用域。在Python中,只有模組(module),類(class)以及函式(def、lambda)才會引入新的作用域。Python的變數名解析機制也稱為 LEGB 法則:本地作用域(Local)→當前作用域被嵌入的本地作用域(Enclosing locals)→全域性/模組作用域(Global)→內建作用域(Built-in)

新式類和舊式類的區別,如何確保使用的類是新式類

為了統一類(class)和型別(type),python在2.2版本引進來新式類。在2.1版本中,類和型別是不同的。

為了確保使用的是新式類,有以下方法:

放在類模組程式碼的最前面 __metaclass__ = type
從內建類object直接或者間接地繼承
在python3版本中,預設所有的類都是新式類。

簡述__new__和__init__的區別

建立一個新例項時呼叫__new__,初始化一個例項時用__init__,這是它們最本質的區別。

new方法會返回所構造的物件,init則不會.

new函式必須以cls作為第一個引數,而init則以self作為其第一個引數.

38.Python垃圾回收機制

Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,通過“標記-清除”(mark and sweep)解決容器物件可能產生的迴圈引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。

1 引用計數

PyObject是每個物件必有的內容,其中ob_refcnt就是做為引用計數。當一個物件有新的引用時,它的ob_refcnt就會增加,當引用它的物件被刪除,它的ob_refcnt就會減少.引用計數為0時,該物件生命就結束了。

優點:簡單 實時性

缺點:維護引用計數消耗資源 迴圈引用

2 標記-清除機制

基本思路是先按需分配,等到沒有空閒記憶體的時候從暫存器和程式棧上的引用出發,遍歷以物件為節點、以引用為邊構成的圖,把所有可以訪問到的物件打上標記,然後清掃一遍記憶體空間,把所有沒標記的物件釋放。

3 分代技術

分代回收的整體思想是:將系統中的所有記憶體塊根據其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率隨著“代”的存活時間的增大而減小,存活時間通常利用經過幾次垃圾回收來度量。

Python預設定義了三代物件集合,索引數越大,物件存活時間越長。

39.Python中的@property有什麼作用?如何實現成員變數的只讀屬性?

@property裝飾器就是負責把一個方法變成屬性呼叫,通常用在屬性的get方法和set方法,通過設定@property可以實現例項成員變數的直接訪問,又保留了引數的檢查。另外通過設定get方法而不定義set方法可以實現成員變數的只讀屬性。

*args and **kwargs

*args代表位置引數,它會接收任意多個引數並把這些引數作為元組傳遞給函式。**kwargs代表的關鍵字引數,允許你使用沒有事先定義的引數名,另外,位置引數一定要放在關鍵字引數的前面。

有用過with statement嗎?它的好處是什麼?具體如何實現?

with語句適用於對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的“清理”操作,釋放資源,比如檔案使用後自動關閉、執行緒中鎖的自動獲取和釋放等。

40. Python是如何進行記憶體管理的?

答:從三個方面來說,一物件的引用計數機制,二垃圾回收機制,三記憶體池機制

一、物件的引用計數機制

Python內部使用引用計數,來保持追蹤記憶體中的物件,所有物件都有引用計數。

引用計數增加的情況:

1,一個物件分配一個新名稱

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

引用計數減少的情況:

1,使用del語句對物件別名顯示的銷燬

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

sys.getrefcount( )函式可以獲得物件的當前引用計數

多數情況下,引用計數比你猜測得要大得多。對於不可變資料(如數字和字串),直譯器會在程式的不同部分共享記憶體,以便節約記憶體。

二、垃圾回收

1,當一個物件的引用計數歸零時,它將被垃圾收集機制處理掉。

2,當兩個物件a和b相互引用時,del語句可以減少a和b的引用計數,並銷燬用於引用底層物件的名稱。然而由於每個物件都包含一個對其他物件的應用,因此引用計數不會歸零,物件也不會銷燬。(從而導致記憶體洩露)。為解決這一問題,直譯器會定期執行一個迴圈檢測器,搜尋不可訪問物件的迴圈並刪除它們。

三、記憶體池機制

Python提供了對記憶體的垃圾收集機制,但是它將不用的記憶體放到記憶體池而不是返回給作業系統

1,Pymalloc機制。為了加速Python的執行效率,Python引入了一個記憶體池機制,用於管理對小塊記憶體的申請和釋放。

2,Python中所有小於256個位元組的物件都使用pymalloc實現的分配器,而大的物件則使用系統的malloc。

3,對於Python物件,如整數,浮點數和List,都有其獨立的私有記憶體池,物件間不共享他們的記憶體池。也就是說如果你分配又釋放了大量的整數,用於快取這些整數的記憶體就不能再分配給浮點數。

41. 什麼是lambda函式?它有什麼好處?

答:lambda 表示式,通常是在需要一個函式,但是又不想費神去命名一個函式的場合下使用,也就是指匿名函式

lambda函式:首要用途是指點短小的回撥函式

lambda [arguments]:expression

>>> a=lambdax,y:x+y

>>> a(3,11)

42.Python裡面如何拷貝一個物件?(賦值,淺拷貝,深拷貝的區別)

答:賦值(=),就是建立了物件的一個新的引用,修改其中任意一個變數都會影響到另一個。

淺拷貝:建立一個新的物件,但它包含的是對原始物件中包含項的引用(如果用引用的方式修改其中一個物件,另外一個也會修改改變){1,完全切片方法;2,工廠函式,如list();3,copy模組的copy()函式}

深拷貝:建立一個新的物件,並且遞迴的複製它所包含的物件(修改其中一個,另外一個不會改變){copy模組的deep.deepcopy()函式}

43.介紹一下except的用法和作用?

答:try…except…except…[else…][finally…]

執行try下的語句,如果引發異常,則執行過程會跳到except語句。對每個except分支順序嘗試執行,如果引發的異常與except中的異常組匹配,執行相應的語句。如果所有的except都不匹配,則異常會傳遞到下一個呼叫本程式碼的最高層try程式碼中。

try下的語句正常執行,則執行else塊程式碼。如果發生異常,就不會執行

如果存在finally語句,最後總是會執行。

44. Python中pass語句的作用是什麼?

答:pass語句不會執行任何操作,一般作為佔位符或者建立佔位程式,whileFalse:pass

45.介紹一下Python下range()函式的用法?

答:列出一組資料,經常用在for  in range()迴圈中、

46.如何用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()一樣,不過它會返回一個二維陣列,包括替換後的新的字串和總共替換的數量

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

48.單引號,雙引號,三引號的區別

答:單引號和雙引號是等效的,如果要換行,需要符號(\),三引號則可以直接換行,並且可以包含註釋

如果要表示Let’s Go 這個字串

單引號:s4 = ‘Let\’s go’

雙引號:s5 = “Let’s go”

s6 = ‘I realy like“python”!’

這就是單引號和雙引號都可以表示字串的原因了