1. 程式人生 > >python基礎知識總結之一

python基礎知識總結之一

1.字符集問題

windows下面儘量用#coding:gbk 
Linux下面儘量用#coding:utf-8

2.什麼是序列

序列是指有序和無序的資料結構 
包括:字串,列表,元組,字典,集合

3.程式設計規範

命名規範: 
類定義用駝峰式  TestCase 
其他用小寫字元加下劃線  test_case 
常量全部用大寫

註釋的兩種方式: 
單行註釋用# 
類和物件的docstring用”“” “”“

import順序: 
標準庫,第三方庫,自定義庫 
不同型別的庫中間空一行

空行: 
類與函式之間空兩行 
函式與函式之間空一行 
函式中,邏輯程式碼段之間空一行

4.庫、包、模組的概念

庫:python的一個專案 
包:包含__init__.py檔案的資料夾 
模組:以.py為結尾的檔案

py2中,包裡面必須有__init__.py檔案,否則直譯器無法識別這個包,也就是包下面的.py檔案,外部無法呼叫。

5.import匯入模組搜尋順序

import匯入的時候,針對模組名,首先搜尋當前目錄,然後查詢標準庫,最後查詢第三方庫。

6.__init__.py檔案的作用

python中__init__.py檔案的作用:Python中每個模組的包下面都有一個__init__.py檔案,有了這個檔案,我們才能匯入這個包下面的module。

7.如何設定環境變數

windows環境:我的電腦-屬性-高階系統設定-高階-環境變數,修改PATH,新增;$PYTHON_INSTALL_DIR(自己改) 
Linux環境:export PATH=…….

8.第三方庫安裝位置  $PYTHON_INSTALL_DIR\Lib\site-packages

9.檢視內建函式:dir(builtins)

10.type和isinstance()函式

Python在定義變數的時候不用指明具體的的型別,直譯器會在執行的時候會自動檢查變數的型別,並根據需要進行隱式的型別轉化。 
因為Python是動態語言,所以一般情況下是不推薦進行型別轉化的。 
比如”+”操作時,如果加號兩邊是資料就進行加法操作,如果兩邊是字串就進行字串連線操作,如果兩邊是列表就進行合併操作,甚至可以進行復數的運算。直譯器會在執行時根據兩邊的變數的型別呼叫不同的內部方法。當加號兩邊的變數型別不一樣的時候,又不能進行型別轉化,就會丟擲TypeError的異常。

但是在實際的開發中,為了提高程式碼的健壯性,我們還是需要進行型別檢查的。而進行型別檢查首先想到的就是用type(),比如使用type判斷一個int型別。

對於內建的基本型別來說,使用tpye來檢查是沒有問題的。 
可是當應用到其他場合的時候,type就顯得不可靠了。比如:

 

class A():
    pass

class B():
    pass

a = A()
b = B()

print(type(a) is type(b))
程式碼的輸出結果: True1234567891011

此例中type的判斷顯然是有問題的。 
這個時候我們就需要使用isinstance來進行型別檢查。

 

isinstance(object, classinfo)1

object表示例項,classinfo可以是直接或間接類名、基本型別或者有它們組成的元組。

 

>>> isinstance(2, float)
False
>>> isinstance('a', (str, unicode))
True
>>> isinstance((2, 3), (str, list, tuple))
True123456

可以參考此博文:https://www.jianshu.com/p/7ef549503c93

11.字典這個序列,以key作為序列中的每一項

 

>>> list({1:2,3:4})
[1, 3]12

12.函式返回值的問題

 

def test():
    print('lijingkuan')

print(test())1234

返回值為

 

lijingkuan
None12

為什麼呢? 
原因是: 
字串’lijingkuan’是test()函式列印的,而None是print()函式列印的, 
None是test()函式的返回值。

修改一下

 

def test():
    print('lijingkuan')
    return 123

print(test())12345

則輸出結果變為

 

lijingkuan
12312

如果不想列印那個None,就直接執行test()就行了,不要print。

13.raw_input函式

接受使用者輸入,返回字串  
—    重要,返回的是字串,不是數字或者其他型別

14.list可以用來儲存任何型別的物件,不強制要求型別相同,是有序的。

15.type和isinstance的區別???

16.list的高階特性 
增刪改查、排序

增: 
append,extend,insert 
append和extend的區別? 
append是往列表中新增一個值,extend是增加一個序列。 
列表a+b會生成一個新的列表,原來的a和b不會變化。 
一般寫作 c=a+b 
a.extend(b)會修改列表a,與a+b有區別。 
a.append(b),會將b當成一個值去對待,而不是當成一個列表。 
例如:

 

a=[1,2,3],b=[4,5,6]
a.extend(b) = [1,2,3,4,5,6]
a.append(b)=[1,2,3,[4,5,6]]123

因此: 
append往列表中新增元素,該元素可以是任何形式的資料結構或物件,新增的物件作為列表中的一個元素,放到最後一位。 
extend用於在列表末尾一次性追加另一個序列中的多個值,不是把物件整個新增,而是拿出每一項來新增。

 

>>> a=[1,2,3]
>>> b="abc"       
>>> a.extend(b)
>>> a
[1, 2, 3, 'a', 'b', 'c'] --字串也是序列
>>> c={'f':1,7:9}
>>> a.extend(c)
>>> a
[1, 2, 3, 'a', 'b', 'c', 'f', 7]  
-- 字典也是序列
-- 當字典作為一個序列的時候,那麼序列的每一項指的是字典的key,不包括value。1234567891011

insert:往列表中新增元素,兩個引數,第一個引數表示insert的位置,第二個引數表示insert的引數的value。

刪: 
remove,pop

 

>>> a
[1, 2, 3, 'a', 'b', 'c', 'f', 7]
>>>
>>>
>>> a.remove(2)
>>> a
[1, 3, 'a', 'b', 'c', 'f', 7]
>>>
>>> a.pop(2)
'a'
>>> a
[1, 3, 'b', 'c', 'f', 7]123456789101112

remove刪除的是具體的value,沒有返回值。 
pop刪除的是索引對應的value,並將刪除的元素返回。 
如果pop()不加引數,刪除的是最後一個元素。 
pop(0),刪除第一個元素

堆疊:坑,先進後出,通過pop()實現 
佇列:通道,先進先出,通過pop(0)實現

改: 
通過賦值去完成(通過索引定位): 
a[2]=5

查: 
1.通過索引 
2.通過index去進行查詢 
3.獲取某個值在列表中的位置

 

>>> a
[1, 3, 'b', 'c', 'f', 7]
>>> a[1]
3
>>> a.index('f')
4123456

排序: 
sort,sorted 
sort不改變列表,sorted改變列表 
sort是列表的方法,對列表中value重新排序,sorted是內建函式,對序列進行排序,輸出排序後的序列。

 

>>> a=[6,2,1,3,9,8]
>>> sorted(a)
[1, 2, 3, 6, 8, 9]
>>> a
[6, 2, 1, 3, 9, 8]
>>> a.sort()
>>> a
[1, 2, 3, 6, 8, 9]12345678

17.list兩種遍歷方式(非常重要)


for item in _list
for index,item in enumerate(_list)

 


>>> a=[5,2,1]
>>> for index,item in enumerate(a):
...     print(index,item)
...
0 5
1 2
2 11234567

18.列表推導式

格式1:【輸出 for  xx  in  序列  if  條件表示式】 
一句話完成列表遍歷,在迴圈中把滿足某些條件的取出來。 
求1-100內能同時除盡2和3的整數

 

--列出10以內的偶數
>>> [x for x in range(0,11) if x%2==0]
[0, 2, 4, 6, 8, 10]

--求1-100內能同時除盡2和3的整數
>>> [x for x in range(1,101) if (x%2==0 and x%3==0)]
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]1234567

格式2:【輸出  if  條件  else  表示式  for  xx  in  序列】 
一句話完成列表編列,在迴圈中把滿足和不滿足某些條件的取出來做處理。

 

--將10以內的奇數平方,偶數減半
>>> [i*i if i%2==1 else int(i/2) for i in range(1,11)]
[1, 1, 9, 2, 25, 3, 49, 4, 81, 5]123

18.__pycache__資料夾儲存之前執行過的.py檔案生成的pyc檔案,如果下次執行.py檔案時發現.py檔案未作修改,則直接去pycache裡面執行pyc檔案,優化python的執行效率。

19.python3中的range相當於python2中的xrange。

20.input和raw_input的區別?

21.列表的切片問題

列表的切片是前閉後開的,即a[1:4],包含1,不包含4。(索引是從0開始的)

22.字串split()函式

split() 方法語法:

 

str.split(str="", num=string.count(str)).

引數
str -- 分隔符,預設為所有的空字元,包括空格、換行(\n)、製表符(\t)等。
num -- 分割次數。

返回值
返回分割後的字串列表。12345678

split()和split(’ ‘)執行結果的差別 
split()將空格,換行符,製表符等作為分隔符,而split(’ ‘)只是將空格作為分隔符。

23.字串比較,in 的用法

兩種情況: 
字串情況下最小單位為字元

 

s = "abc 123"
ret = "ab" in s
print (ret)123

陣列情況下最小單位是每個字串

 

li = ["tom","rose","jack"]
ret = "to" not in li
print (ret)123

24.字典

用大括號包括,用逗號分隔每個鍵值對,鍵值對之間用冒號連線 
鍵是不可改變的資料結構(不是隨便一個型別的資料都可以當鍵的),值可以是任意的物件 
a={} 
a=dict()

使用: 
普通查詢,引數校驗: 
字典的訪問是通過key去取value 
a={1:2,’haha’:e} 
a[‘haha’]   如果沒有這個key,執行會報錯,可用於引數校驗 
a.get(‘haha’)   如果沒有這個key,返回值為null 
注意兩者的區別。

增加、修改 
直接賦值,setdefault,update 
a[‘test’]=’diyige’  既可以增加,又可以修改 
a.setdefault()  增加一個新的key value,如果key存在,則value不更新 
a.update(k,v)效果跟直接賦值一樣

setdefault()用法:

 

語法
setdefault()方法語法:

dict.setdefault(key, default=None)
引數
key -- 查詢的鍵值。
default -- 鍵不存在時,設定的預設鍵值。
返回值
如果字典中包含有給定鍵,則返回該鍵對應的值,否則返回為該鍵設定的值。123456789

刪除: 
pop(key) 
刪除指定給定鍵所對應的值,返回這個值並從字典中把它移除。注意字典pop()方法與列表pop()方法作用完全不同。

字典的遍歷:兩種(三種) 
(1)for item in _dict: 
              print item 
輸出的是key,不輸出value,因為遍歷的時候是吧字典當序列遍歷

(2)for k,v in a.items(): 
               print(k,v)

(3) for item in a.values()  –只遍歷values,基本用不到

25.列表中的字串過濾問題

startwith()

 

描述
Python startswith() 方法用於檢查字串是否是以指定子字串開頭,如果是則返回 True,否則返回 False。
如果引數 beg 和 end 指定值,則在指定範圍內檢查。

語法
startswith()方法語法:

str.startswith(str, beg=0,end=len(string));
引數
str -- 檢測的字串。
strbeg -- 可選引數用於設定字串檢測的起始位置。
strend -- 可選引數用於設定字串檢測的結束位置。
返回值
如果檢測到字串則返回True,否則返回False。1234567891011121314

內建函式:filter(function_name,sequence) 
將sequence中的每一項作為引數傳遞給function,即function(item) 
在python2中,將符合條件的(執行結果為True),返回list ,tuple或者dict(需要驗證,是否只返回列表),視sequence的型別而定,迴圈遍歷取出。 
在python3中,將執行結果為True的item,返回一個filter的物件,使用迴圈遍歷取結果。

26.元組

列表是[],元組是(),都是有序的,元組建立之後無法修改,而列表是可以修改的。 
元組的表示是逗號‘,’不是括號(),也就是說,不是加了()就是元組,而是要有,逗號,具體解釋的舉例如下:

 

>>> a=(1,2,3)
>>> type(a)
<class 'tuple'>
>>>
>>> a= 1,2,3
>>> type(a)
<class 'tuple'>

>>> a=(1)
>>> b=(1,)
>>> type(a)
<class 'int'>
>>> type(b)
<class 'tuple'>
>>> c=1,
>>> type(c)
<class 'tuple'>1234567891011121314151617

元組和列表一樣,通過下標訪問。

元組的使用場景: 
1.函式返回多項 
    return a,b 
 2.if a in b(b是一個元組) 
 或者if a in (‘test1’,’hello’,’gaga’,) 
 – 參考前面提到過的 in 的使用

27.集合 set

描述元素種類的一種無序序列,內建函式set 
1.沒有重複項 
2.無序

 


>>> a='hello'
>>> set(a)
{'e', 'l', 'o', 'h'}
>>> a=set({1:2,4:5})
>>> a
{1, 4}1234567

集合和列表的轉換 
集合的一些運算,其他的序列可能沒有,普通列表可能需要使用集合的特徵進行運算,比如求兩個列表的交集,差集,並集等等

 

>>> a=[1,2,3,4,5,6,7]
>>> b=[5,7,9]
>>>
>>> set(a) & set(b)
{5, 7}
>>>
>>> set(a) | set(b)
{1, 2, 3, 4, 5, 6, 7, 9}
>>>
>>> set(a) - set(b)
{1, 2, 3, 4, 6}1234567891011

應用:比如IP去重 
set作為序列遍歷 
for item in set:

28.函式

排名問題

29.字串前面加 ‘r’ 的作用

開啟檔案時open(r’d:\hello\hello.txt’) 
不加r會報錯,因為系統認為\是轉義符

30.函式

def func_name(paras): 
    return 

引數有幾種? 
普通引數 ,預設引數, 可變長引數

* args代表元組,會把所有沒有指定key的引數,把這一類引數放到一個元組中 
* *  kwargs代表字典,會把所有指定key的引數,放到字典中

 

>>> def test_args(*args, **kwargs):
...     print(args,kwargs)
...
>>> test_args(5,c=8)
(5,) {'c': 8}
>>> test_args(5,8,c=8,d=9)
(5, 8) {'c': 8, 'd': 9}

>>> def test_args(*args, **kwargs):
...     return args,kwargs
...
>>> test_args(5,8,c=8,d=9)
((5, 8), {'c': 8, 'd': 9})
--上面的返回結果中多了最外邊的兩個括號,原因是return返回的是元組(元組的應用之一)1234567891011121314

31.深拷貝

迴圈遍歷中的刪除問題 
將列表中字串的項刪除

 

_list = [1,'aa','123','test',8,9,7]

def filter_str(item):
    if isinstance(item,str):
        return False
    else:
        return True
#    return not isinstance(item,str):
ret = []
rst = filter(filter_str, _list)
for item in rst:
    ret.append(item)

print(ret)1234567891011121314

深度拷貝(補充程式碼在github上deep_copy.py)

32.巢狀函式  &  匿名函式

可程式設計引數  -> 函數語言程式設計  ->  巢狀函式  ->  閉包  ->  裝飾器

 

def test(m,n):
    return m+n

def func(func_name, *args, **kwargs):
    ret = func_name(*args, **kwargs):
    return ret+1

print(test(8,9))
print(func(test,8,9))123456789

巢狀函式(子函式):函式體裡面包含另一個函式的完整定義 
應用場景:一個函式中有一小段邏輯被多次呼叫 
                  閉包,裝飾器

子函式能夠呼叫父函式的區域性變數,父函式無法呼叫子函式的區域性變數 
參考github中qiantao*.py

匿名函式(lambda函式): 
定義:lambda跟一個或多個引數,跟著冒號,接著是一個表示式。 
lambda是一個關鍵字,lambda冒號前邊是引數,後邊返回結果 
形式:lambda x,y:x+y 
應用場景: 
函數語言程式設計中,函式名本應由對應的實現邏輯,對於簡單的邏輯,可以用一個lambda來表示。 
更多的應用,是和一些內建函式進行搭配,比如filter,map,sorted 
舉例: 
排名問題(下) 參考github上paiming.py

 

>>> func_name = lambda x,y : x+y
>>> func_name
<function <lambda> at 0x0000000001D31E18>  --注意:返回的是函式名
>>> func_name(1,2)
3
>>>
效果和下面的相同
def add(x, y):
    return x,y
add(1,2)
相同點,區別是什麼?
相同點:
完成的作用相似
區別:
lambda返回的是一個函式名
正常函式返回的是結果12345678910111213141516

33.內建函式 map 
map(function, sequence)

定義:對sequence中的item依次執行function(item),將執行結果返回一個map迭代物件,可以通過list放入列表中

舉例:輸出1到15的所有數的平方 
參考github中pingfang.py

34.函數語言程式設計

定義:對別的函式進行封裝,運算,操作的函式 
學習目的: 
(1)需要對別的函式進行封裝 
(2)看原始碼(看別人的程式碼) 
引數: 
(1)支援傳別的函式名 
(2)任意引數*args ,**kwargs 
應用場景: 
(1)對一件事進行封裝 
(2)閉包、裝飾器(以後講) 
標識:引數是其他函式的函式名 
典型的使用了函數語言程式設計的內建函式:sorted,map,filter

35.直譯器載入指令碼順序

 

執行指令碼中的某個函式,例如run(),可以使用以下兩種寫法,區別是什麼?
(1)
if __name__ == "__main__":
    run()

(2)
run()1234567

參看下面的指令碼:

 

#coding:gbk
#python直譯器載入檔案的順序

var1 = 1
var2 = 2

def test():
    print("執行test")

def test1():
    print("執行test1")

print(var1)
test1()

if __name__ == '__main__':
    print(var2)
    test()

我原本以為會先執行main函式,再執行指令碼中其他的函式,輸出
2
執行test
1
執行test1

但實際執行結果是,先執行前面的程式碼,最後執行的main,輸出
1
執行test1
2
執行test123456789101112131415161718192021222324252627282930

結論: 
程式程式碼入口,並不是程式開始執行時第一個執行的。在其他語言中也是同樣的道理。 
順序: 
(1)載入import模組 
(2)載入全域性變數,全域性物件 
(3)載入函式名(註冊函式名,不執行函式體)。如果有函式執行的話,就直接執行。 
(4)if name == ‘main‘:

因為: 
全域性變數:存放在記憶體的靜態區域(對於你的整個程式碼可見) 
區域性變數:存放在記憶體的棧中,函式執行完即銷燬

35.全域性變數global,區域性變數

全域性變數:位置在全域性區域的變數 
區域性變數:在函式內的變數

函式的作用域: 
L (Local) 區域性作用域 
G (Global) 全域性作用域

以 L –> G 的規則查詢,即:在區域性找不到,便會去區域性外的區域性找,在找不到就會去全域性找。

 

var = 12

def change_var():
#    global var
    var = 13
    return var

print(change_var())
print(var)

輸出結果:
把global註釋掉,輸出 13,12
不註釋global,輸出13,13
可以通過在程式碼中新增print(id(var))來看看,各個變數var的地址是否相同
123456789101112131415

(1)如果函式中的變數與全域性變數重名的話,直譯器會把函式內的變數當成區域性變數,重名歸重名,但不是同一個變數 
(2)如果想修改全域性變數,需要通過關鍵字global去宣告這個變數,這樣就可以在函式中修改全域性變數,一旦在函式中加了global,則這個函式中,這個名字的變數都是用的全域性變數

結論:自己定義的函式變數,不要跟全域性變數重名

36.內建函式eval,是把字串當做命令去執行

參考部落格:https://www.cnblogs.com/dadadechengzi/p/6149930.html 
部落格中有更多示例

內建函式eval,是把字串當做命令去執行 
將字串str當成有效的表示式來求值並返回計算結果 
函式定義:

 

eval(expression, globals=None, locals=None)1

引數 
expression:是一個參與計算的python表示式 
globals: – 變數作用域,全域性名稱空間,是可選的引數,如果設定屬性不為None的話,就必須是dictionary物件了 
locals也:– 變數作用域,區域性名稱空間,是一個可選的物件,如果設定屬性不為None的話,可以是任何map物件了

返回值 
返回表示式計算結果。

eval(expression, globals=None, locals=None)  — 官方文件中的解釋是,將字串str當成有效的表示式來求值並返回計算結果。globals和locals引數是可選的,如果提供了globals引數,那麼它必須是dictionary型別;如果提供了locals引數,那麼它可以是任意的map物件。

python是用名稱空間來記錄變數的軌跡的,名稱空間是一個dictionary,鍵是變數名,值是變數值。 
當一行程式碼要使用變數 x 的值時,Python 會到所有可用的名字空間去查詢變數,按照如下順序: 
1)區域性名字空間 - 特指當前函式或類的方法。如果函式定義了一個區域性變數 x, 或一個引數 x,Python 將使用它,然後停止搜尋。 
2)全域性名字空間 - 特指當前的模組。如果模組定義了一個名為 x 的變數,函式或類,Python 將使用它然後停止搜尋。 
3)內建名字空間 - 對每個模組都是全域性的。作為最後的嘗試,Python 將假設 x 是內建函式或變數。 
python的全域性名字空間儲存在一個叫globals()的dict物件中;區域性名字空間儲存在一個叫locals()的dict物件中。我們可以用print (locals())來檢視該函式體內的所有變數名和變數值。

example:

 

a=1
g={'a':20}
eval("a+1",g)   -- 這裡的g,就是全域性名字空間中的dict,g={'a':20}
-- 返回21


#test eval() and locals()
x = 1
y = 1
num1 = eval("x+y")
print (num1)

def g():    
    x = 2    
    y = 2  
    num3 = eval("x+y")    
    print (num3)        
    num2 = eval("x+y",globals())   
    #num2 = eval("x+y",globals(),locals())    
    print (num2)

g()

print locals()["x"]
print locals()["y"] 
print globals()["x"]
print globals()["y"]

num1的值是2;num3的值也很好理解,是4;
num2的值呢?由於提供了globals()引數,那麼首先應當找全域性的x和y值,也就是都為1,那麼顯而易見,num2的值也是2。
如果註釋掉該句,執行下面一句呢?根據第3)點可知,結果為412345678910111213141516171819202122232425262728293031

eval函式的妙用: 
eval函式就是實現list、dict、tuple與str之間的轉化 
str函式把list,dict,tuple轉為為字串

字串轉換成列表

 

>>> a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"
>>> print(type(a))
<type 'str'>
>>> b = eval(a)
>>> type(b)
<type 'list'>
>>> print(b)
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]
>>> 123456789

字串轉換成字典

 

>>> a = "{1: 'a', 2: 'b'}"
>>> print(type(a))
<type 'str'>
>>> b = eval(a)
>>> print(type(b))
<type 'dict'>
>>> print(b)
{1: 'a', 2: 'b'}
>>> 123456789

字串轉換成元組

 

>>> a = "([1,2], [3,4], [5,6], [7,8], (9,0))"
>>> print(type(a))
<type 'str'>
>>> b=eval(a)
>>> print(type(b))
<type 'tuple'>
>>> print(b)
([1, 2], [3, 4], [5, 6], [7, 8], (9, 0))
>>> 123456789

37.類的初步認識

 

class ClassName(FatherClass):
    def __init__(self, class_args1):
        self.class_args1 = class_args1

   def class_func(self):
       return123456

類例項 ==類物件 
類引數寫在__init__裡(而不是寫在類名後面的括號裡,與其他語言不同)類後面的括號中寫的是類繼承的父類 
類裡面所有的函式第一個引數要寫成self(不要問為什麼,照做就是了),凡是有self的函式,都是類例項函式 
self其實是類例項物件

38.初始化 def  __init__(self):

格式: 

 

    def __init__(self, a):
        print(111)
        self.a =a 123

當類初始化的時候,比如 a = A(‘ss’) 
這個操作會打印出111,因為這個操作會執行init()函式

作用:類傳參的地方,例如a,呼叫的時候要傳入引數 
用法:類例項屬性(例如self.a)在類的整個範圍內都可以使用

初始化例項物件的時候會執行__init__函式

39.類屬性  && 類例項屬性

類屬性,不需要初始化例項物件就可以使用 
類例項屬性,在__init__()函式的列表中,需要有了例項物件之後才能呼叫

在程式載入過程中,類屬性和類定義,函式一樣,會被載入(註冊),類例項屬性不會,類例項方法會註冊,但不執行函式體。

類屬性的位置:在__init__函式的前面 
類屬性使用場景: 
類似於其他語言中的靜態引數,參看41

40.繼承

參考github指令碼class_inherint.py

41.類屬性的應用場景

參考 db_conn_class_property.py

42.訪問控制 public, protected,private

在Java,C++,以及PHP中都有對應的關鍵字,public,protected,private,但是在Python中卻沒有這些關鍵字來宣告類成員的訪問作用域。

在Python中是通過一套命名體系來識別成約的訪問範圍的  
protected: _  函式名開頭是一個下劃線 
private: __     函式名開頭是兩個下劃線

在python中所有的以字母開頭的成語名稱被python命名體系自動識別為public,單個下劃線開頭的成員被識別為protected,最後雙下劃線開頭的成員被識別為private。

另外,Python不支援諸如C++, Java的根據引數型別與數目的不同而進行的過載(overload),即只以函式名字做為函式身份的判斷,不會依據引數。而且如果出現多個同名函式(不論引數是否數目相同),則以最後一個為準(即後出現的函式將之前的同名函式覆蓋)。

參考 protected_private.py

43, python中的self其實就是類例項物件本身

參考 self.py

44.單例

監控程式,每次都要建立一個新的資料庫連線,監控頻繁情況下,需要建立很多很多連線,這個問題如何解決: 
(1)使用前面提到的類屬性 
(2)初始化一個類物件,放到全域性物件位置,其他想使用類的地方直接使用此物件 
(3)單例(專業處理連線多的問題) 
(4)資料庫連線池

單例模式,在類被執行的才連線,不想類屬性或者全域性類物件一樣,程式載入的時候就連線 
是一個函式封裝 
通過裝飾器的方式呼叫

場景:通過單例解決mysql等服務連線過多的問題

思路: 
先判斷例項是否已經初始化 
如果已經初始化了物件,直接使用初始化的物件 
如果沒有,則初始化

參考singleton.py

45.閉包

閉包就是你呼叫了一個函式a,這個函式a返回了一個子函式名字b給你,這個返回的函式b就叫做閉包。

 

def a():

    def b():
        return 1

   return b123456

所以,通俗的講,閉包就是,返回子函式名 
作用:使用子函式之外的父函式的變數 
參考 bibao.py

閉包到底是幹嘛的?一般用來做裝飾器

46.裝飾器

閉包+函數語言程式設計 = 裝飾器

例子參看第五課 6-裝飾器.avi

47.python中執行shell指令

執行狀態(執行成功或失敗)和執行結果:code,result 
os.system() 返回code,result輸出在console中

>>> 
>>> import os
>>> ret = os.system("free -m")
             total       used       free     shared    buffers     cached
Mem:         70619       9497      61122          0        212       1510
-/+ buffers/cache:       7774      62845
Swap:         4095          0       4095
>>> print(ret)
0


import commands
ret = commands.getoutput(shell指令或者指令碼)
code,ret = commands.getstatusoutput(shell指令或者指令碼)
命令不同,返回值的數量不同123456789101112131415

py3中,將commands模組融合在了subprocess模組中

48.執行緒

執行緒能否殺死?正常情況下是不能的。 
執行緒安全問題如何解決?鎖。 
多執行緒使用鎖的話,多執行緒是不是就成了串行了?只是某一時刻或某一部分序列 
執行緒的作用是什麼?非同步、併發

Threading模組

需要掌握老師提供的指令碼

t = threading.Thread(target=func_name,args=[]) 
t.start

target是需要多執行緒執行的函式,args是函式的引數

原生呼叫的內部原理: 
start觸發,run是真正執行的 
預設是等待子執行緒退出,主執行緒才退出(程序在執行完所有程式碼時,子執行緒還未執行完,程序要等待子執行緒執行完再退出) 
如果setDaemon(True),則不等待(要在子執行緒start之前設定,否則會報錯:RuntimeError: cannot set daemon status of active thread)

主執行緒退出後,子執行緒就沒了

#不帶引數
import time
import threading

def sleep():
    time.sleep(5)
    print('5 second')
    return 'money'

t = threading.Thread(target=sleep)
#t.setDaemen(True)
t.start()


#帶引數
import time
import threading

def sleep(n):
    time.sleep(n)
    print('sleep %s second' % n)
    return 'money'

t = threading.Thread(target=sleep, args=[3])
# t = threading.Thread(target=sleep, args=(3,)) 元組必須加逗號
t.start()


#如何獲得執行緒中的返回值?
#一般很難獲得執行緒中結果,但是如果工作中需要獲得結果,怎麼辦?
#這種需求很少
#1.寫入資料庫
#2.

# 原生執行緒的兩個缺點:
#1.傳參不得勁兒(用列表還好,用元組容易出錯(單個引數沒加逗號))
#2.函式的返回值無法獲取
1234567891011121314151617181920212223242526272829303132333435363738

join 
使得執行緒阻塞到函式執行完成後,主執行緒才繼續進行 
後者傳入一個引數,表明阻塞時間,超過該時間之後,就不阻塞了,可以繼續執行(不用等執行緒執行完成) 
參考thread_join。py 
使用場景是在多執行緒中,多個執行緒join,總執行時間,是幾個執行緒中執行時間最長的執行緒的執行時間。

鎖:

 

from threading import lock

lock = Lock()
lock.acquire()
lock.release()12345

執行緒池:

 

from concurent.futures import ThreadPoolExecutor
t = ThreadPoolExecutor(num)
t.submit(func_name)123

49.佇列

佇列的作用: 
非同步:點贊業務(對於實時性要求不是很高,並且對資料庫操作) 
系統解耦:訂單系統,發貨系統 
緩衝流量:秒殺

在python中使用佇列 
py2.7  Queue 
py3.x  queue

建立:queue.Queue(maxsize)
往佇列中存放元素:put(obj)
取元素:get() 按順序取,所以不需要引數
enpty()

import Queue
import time

q = Queue.Queue()

for i in range(10):
    q.put(i)

while not q.empty():
    print(q.get())
    time.sleep(0.5)12345678910111213141516

50.異常處理

(1)異常拋錯機制 
 – 程式執行異常,直譯器會首先看當前的執行環境(函式或類)有沒有捕獲這個異常,有沒有try。 
 – 當函式裡沒有找到的話,它會將異常傳遞給上層的呼叫函式,看看那裡有沒有處理。 
 – 如果在最外層(全域性‘main’)還是沒有找到的話,直譯器就會退出,同時打印出traceback資訊在標準錯誤裡。 
 注:當異常發生的時候 
 – 程式碼異常,當前執行流終止,退出 
 – 異常資訊會列印在標準錯誤裡

怎麼樣才能不讓使用者看到報錯棧資訊,自己又能捕獲到報錯棧資訊呢?可以通過如下形式

import traceback
print(str(traceback.format_exc())) --可以儲存到一個變數裡面,記錄在日誌裡12

(2)異常資訊的組成 
Traceback資訊 + 出錯型別 + 出錯原因

(3)捕獲異常的場景 
 – 允許程式碼發生某種型別的異常不需要終止程式碼,可以捕獲異常,繼續往下走。 
 – 建立資料庫連線或者其他的元件連線,使用完不管程式碼是否異常,都要關閉連線 
 – 執行緒中,程式碼要進行異常捕獲 
 – 指令碼:入口函式處 
 – 需要捕獲異常資訊用於展示:程式碼發生異常的時候,需要將異常資訊彙報給上層系統,例如程式碼部署指令碼,部署上百個機器,不可能通過登入機器去查詢報錯

(4)捕獲異常的5種方式 
 – try 。。。 except 。。。     最常用的一種 
 – try… except Exception as e: …print(e)  列印資訊不全,只打印報錯資訊 
 – try … except 特定的異常 print 
 – try…except … finally … 
 –