1. 程式人生 > 遊戲 >《樂高星球大戰:天行者傳奇》獲得兩個新角色DLC包

《樂高星球大戰:天行者傳奇》獲得兩個新角色DLC包

Python教程

1 Python基本語法

R語言 - 包更多,功能拓展更豐富程式設計更復雜,容易出錯

Python - 簡潔、遍歷、不易錯性,是火爆市場的不二法門

學習Python程式設計的利器:
Python官方文件:https://www.python.org/doc/

iPython:https://www.ipython.org/

jupyter notebook:http://jupyter-notebook.readthedocs.io/cn/latest/

Pycharm:https://www.jetbrains.com/pycharm/

Pip:https://pip.pypa.io/en/stable/installing/

基本資料型別:

  • 整數(int)
  • 浮點數(float)
  • 字串(str)
  • 布林值(bool)

具體效果如圖:

注意:truefalse不是bool型別,TrueFalse為bool型別

可以通過以下命令將字元進行轉換

int('8')

輸出結果為數字型別的8。

同理,如圖:

示例:

# 網路頻寬計算
bandwidth = 100
ratio = 8
print(bandwidth / ratio)

注意:Python對於單引號和雙引號沒有區分,如果想用引號的巢狀,需要用雙引號。

對於不懂的函式可以通過help(語法)來進行學習。

為了寫出的程式碼非常美觀,應當儘量滿足PEP8規範:

https://peps.python.org/pep-0008/

2 序列

2.1 序列的概念

序列:指的是它的成員都是有序排列並且可以i通過下表偏移量訪問到它的一個或幾個成員

字串列表元組三種類型都屬於序列

  • 字串:“abcd”
  • 列表:[0,"abcd"]
  • 元組:("abc","def")

2.2 字串的定義和使用

示例1:

# 記錄生肖,根據年份判斷生肖
chinese_zodiac = '鼠牛虎兔龍蛇馬羊猴雞狗豬'
print(chinese_zodiac[0:4])  # 訪問的下標是0-3,輸出的是 鼠牛虎兔
print(chinese_zodiac[-1])  # 輸出的是 豬
print(chinese_zodiac[-3])  # 輸出的是 雞

示例2:

# 記錄生肖,根據年份判斷生肖
chinese_zodiac = '猴雞狗豬鼠牛虎兔龍蛇馬羊'
year = 2022
print(year % 12) # 輸出 6
print(chinese_zodiac[year % 12]) # 輸出 虎

字串的常用操作

  1. 成員關係操作符 in not in 示例:物件 [not] in 序列
  2. 連線操作符 + 示例:序列 + 序列
  3. 重複操作符 * 示例:序列 * 序列
  4. 切片操作符 [:] 示例:序列[0:整數]

示例:

# 記錄生肖,根據年份判斷生肖
chinese_zodiac = '猴雞狗豬鼠牛虎兔龍蛇馬羊'

# 成員關係操作符
print('狗' not in chinese_zodiac)  # 輸出為 False
# 連結操作符
print(chinese_zodiac + chinese_zodiac)  # 輸出為 猴雞狗豬鼠牛虎兔龍蛇馬羊猴雞狗豬鼠牛虎兔龍蛇馬羊
print(chinese_zodiac + 'abcd')  # 輸出為 猴雞狗豬鼠牛虎兔龍蛇馬羊abcd
# 重複操作符
print(chinese_zodiac * 3)  # 輸出為 猴雞狗豬鼠牛虎兔龍蛇馬羊猴雞狗豬鼠牛虎兔龍蛇馬羊猴雞狗豬鼠牛虎兔龍蛇馬羊
# 切片操作符
print(chinese_zodiac[0:2])  # 輸出為 猴雞

注意:列表和元組的區別,列表中的資料可以變更,元組中的資料不能變更。

2.2 元組的定義和常用操作

示例:在Python的shell中輸入以下程式碼:

a=(1,3,5,7)
b=4
filter(lambda x: x < b , a) #輸出為 <filter object at 0x000002715049DB40>
list (filter(lambda x: x < b , a)) #輸出為 [1, 3]
len(list (filter(lambda x: x < b , a))) #輸出為 2
b=6
len(list (filter(lambda x: x < b , a))) #輸出為 3
b=8
len(list (filter(lambda x: x < b , a))) #輸出為 4

效果如圖:

示例:

zodiac_name = ('魔羯座', '水瓶座', '雙魚座', '白羊座', '金牛座', '雙子座',
               '巨蟹座', '獅子座', '處女座', '天秤座', '天蠍座', '射手座')
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22),
               (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
(month, day) = (2, 15)
zodiac_day = filter(lambda x: x <= (month, day), zodiac_days)
print(zodiac_day) # 輸出 <filter object at 0x000001B54FF3BF10>
print(list(zodiac_day))# 輸出 [(1, 20)]

2.3 列表的定義和常用操作

示例:

a_list=['abc','xyz']
a_list.append('X')
print(a_list) #輸出為 ['abc', 'xyz', 'X']
a_list.remove('xyz')
print(a_list) #輸出為 ['abc', 'X']

3 條件與迴圈

3.1 條件語句

條件語句:if

使用方法:

if 表示式: 
	程式碼塊

if 表示式: 
	程式碼塊 
elif 表示式:
	程式碼塊
else:
	程式碼塊

示例1:

x = 'abc'
if x == 'abc':
    print('x的值和abc相等')  # 輸出 x的值和abc相等

示例2:

x = 'abcd'
if x == 'abc':
    print('x的值和abc相等')
else:
    print('x的值和abc不相等')  # 輸出 x的值和abc不相等

示例3:

x = 5
if x < 5:
    print('x<5>')
elif x == 5:
    print('x=5')  # 輸出 x=5
else:
    print('x>5')

示例4:

chinese_zodiac = '猴雞狗豬鼠牛虎兔龍蛇馬羊'
year = int(input('請使用者輸入出生年份'))
if chinese_zodiac[year % 12] == '狗':
    print('狗年運勢')  # 輸入:2018 輸出: 狗年運勢

3.2 迴圈語句

3.2.1 for語句

for語句使用方法:

for 迭代變數 in 可迭代物件:
	程式碼塊

示例:

chinese_zodiac = '猴雞狗豬鼠牛虎兔龍蛇馬羊'
for cz in chinese_zodiac:   #不需要定義變數cz,預設從第一個字元開始
    print(cz)  # 輸出 猴雞狗豬鼠牛虎兔龍蛇馬羊
for i in range(13):
    print(i)   # 輸出 0 1 2 3 4 5 6 7 8 9 10 11 12
for j in range(1, 13):
    print(j)   # 輸出 1 2 3 4 5 6 7 8 9 10 11 12
for year in range(2000, 2019):
    print('%s 年的生肖是 %s' % (year, chinese_zodiac[year % 12]))   # 輸出 2000年的生肖是龍 2001年的生肖是蛇 ...

示例2:

zodiac_name = ('魔羯座', '水瓶座', '雙魚座', '白羊座', '金牛座', '雙子座', '巨蟹座', '獅子座', '處女座', '天秤座', '天蠍座', '射手座')
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22),
               (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
int_month = int(input('請輸入月份:'))
int_day = int(input('請輸入日期:'))
for zd_num in range(len(zodiac_days)):  # len是計算列表的長度 range是取值範圍
    if zodiac_days[zd_num] >= (int_month, int_day):
        print(zodiac_name[zd_num])
        break
    elif int_day == 12 and int_day > 23:
        print(zodiac_name[0])
        break

輸出結果:

3.2.2 while語句

while語句使用方法:

while 表示式: 
	程式碼塊

示例:

number = 8
while True:
    print(number)
    number = number + 1
    if number == 12:
        break
    if number > 10:
        print('a')
        continue

執行結果為: 8 9 10 a 11

示例2:

zodiac_name = ('魔羯座', '水瓶座', '雙魚座', '白羊座', '金牛座', '雙子座', '巨蟹座', '獅子座', '處女座', '天秤座', '天蠍座', '射手座')
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22),
               (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
int_month = int(input('請輸入月份:'))
int_day = int(input('請輸入日期:'))
n = 0
while zodiac_days[n] < (int_month, int_day):
    if int_month == 12 and int_day > 23:
        break
    n += 1
print(zodiac_name[n])

執行結果:

4 對映與字典

4.1 字典的定義和常用操作

對映的型別:字典

字典包含雜湊值和指向的物件。

使用方法:{"雜湊值":"物件"} 例如:{'length':180, 'width':80}

示例:

dict1 = {}
print(type(dict1))
dict2 = {'x': 1, 'y': 2}
dict2['z'] = 3
print(dict2)

執行結果:

示例2:

chinese_zodiac = '鼠牛虎兔龍蛇馬羊猴雞狗豬'
zodiac_name = ('魔羯座', '水瓶座', '雙魚座', '白羊座', '金牛座', '雙子座',
               '巨蟹座', '獅子座', '處女座', '天秤座', '天蠍座', '射手座')
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22),
               (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))

cz_num = {}
for i in chinese_zodiac:
    cz_num[i] = 0
z_num = {}
for i in zodiac_name:
    z_num[i] = 0

while True:

    year = int(input('請輸入年份:'))
    month = int(input('請輸入月份:'))
    day = int(input('請輸入日期:'))

    n = 0
    while zodiac_days[n] < (month, day):
        if month == 12 and day > 23:
            break
        n += 1
    # 輸出生肖和星座
    print(zodiac_name[n])
    print('%s 年的生肖是 %s' % (year, chinese_zodiac[(year + 8) % 12]))
    cz_num[chinese_zodiac[(year + 8) % 12]] += 1
    z_num[zodiac_name[(year + 8) % 12]] += 1

    # 輸出生肖和星座的統計資訊
    for each_key in cz_num.keys():   # 通過 .keys 取出所有的key
        print('生肖 %s 有 %d 個' %
              (each_key, cz_num[each_key]))  # 字串輸出用%s,整數輸出用%d

    for each_key in z_num.keys():
        print('星座 %s 有 %d 個' % (each_key, z_num[each_key]))  # 字串輸出用%s,整數輸出用%d

4.2 列表推導式與字典推導式

示例:

# 從 1 到 10 的所有偶數的平方
# 列表推導式
# 方法一:傳統方法
alist = []
for i in range(1, 11):
    if ((i % 2) == 0):
        alist.append(i*i)
print(alist)
# 方法二:列表推導式
blist = [i*i for i in range(1, 11) if(i % 2) == 0]
print(blist)

# 字典推導式
zodiac_name = ('魔羯座', '水瓶座', '雙魚座', '白羊座', '金牛座', '雙子座',
               '巨蟹座', '獅子座', '處女座', '天秤座', '天蠍座', '射手座')
z_num = {}
for i in zodiac_name:
    z_num[i] = 0
print(z_num)

z_num = {i: 0 for i in zodiac_name}
print(z_num)

5 檔案和輸入輸出

使用Python對檔案進行基本的讀寫操作:

  • 開啟檔案 open()
  • 輸入 read()
  • 輸入一行 readline()
  • 檔案內移動 seek()
  • 輸出 write()
  • 關閉檔案 close()

示例:

# 將小說的主要人物記錄在檔案中
file1 = open('name.txt', 'w')  # 如果沒有標註開啟的模式,預設以只讀的方式開啟  w是寫入
file1.write('諸葛亮')
file1.close()

file2 = open('name.txt')  # 以只讀的方式開啟
print(file2.read())
file2.close()

file3 = open('name.txt', 'a')  # 如果直接寫,會將原有的內容覆蓋掉,用 a 用來增加內容
file3.write('劉備')
file3.close()

file4 = open('name.txt')
print(file4.readline())

file5 = open('name.txt')
for line in file5.readlines():
    print(line)
    print('**********')

執行輸出:

同時會產生一個name.txt檔案,檔案內容為:

諸葛亮劉備

示例2:讀取多行

file4 = open('name.txt')
print(file4.readline())  #讀取第一行
file4.close()

file5 = open('name.txt')
for line in file5.readlines():
    print(line)  # line已經代表每一行的值
file5.close()

執行結果:

示例3:

file6 = open('name.txt')
print('當前檔案指標的位置 %s ' % file6.tell())  # 告訴檔案游標在什麼位置
print('當前讀取了一個字元 %s ' % file6.read(4))  # 告訴檔案游標在什麼位置
print('當前指標的位置 %s ' % file6.tell())  # 告訴檔案游標在什麼位置
# seek()中如果有兩個引數,第一個引數代表偏移的位置,第二個引數 0 表示從檔案開頭偏移  1 表示從當前位置偏移  2 表示從檔案結尾
# file6.seek(0)  #表示游標回到檔案開頭
print(file6.seek(6, 0))
print('當前檔案指標的位置 %s ' % file6.tell())  # 告訴檔案游標在什麼位置
print('我們進行了seek操作')  # seek中可以填寫兩個引數,第一個為偏移位置,當前的位置  file6.seek(0)為回到指標0
print('當前檔案指標的位置 %s ' % file6.tell())  # 告訴檔案游標在什麼位置
print('當前讀取了一個字元 %s ' % file6.read(1))  # 告訴檔案游標在什麼位置
print('當前指標的位置 %s ' % file6.tell())  # 告訴檔案游標在什麼位置
file6.close()

執行結果:

6 錯誤和異常

錯誤 ≠ 異常

異常是在出現錯誤時採用正常控制流以外的動作

異常處理的一般流程是:檢測到錯誤,引發異常;對異常進行捕獲的操作

使用方法:

try:
	<監控異常>
except Exception[, reason]:
	<異常處理程式碼>
finally:
	<無論異常是否發生都執行>

示例1:

try:
    year = int(input('input year:'))
except ValueError:
    print('年份要輸入數字:')

執行結果:

可以通過組成元組來進行多個錯誤捕獲:except (ValueError, AttributeError, KeyError, ZeroDivisionError)

示例2:

try:
    print(1 / 0)
except (ValueError, AttributeError, KeyError, ZeroDivisionError) as e:
    print('這裡對異常捕獲 %s' % e)

這裡將錯誤提示資訊重新命名為變數,並進行列印,常用於除錯時的錯誤資訊提示。

執行結果:

示例3:

try:
    print(1 / 'a')
except Exception as a:
    print('%s' % a)

執行結果:

示例4:可以通過raise來自定義錯誤型別

try:
    raise NameError('helloError')  # 可以自己定義錯誤資訊
except NameError:
    print('my custom error')

示例5:

try:
    aaa = open('name1.txt')  # 可以自己定義錯誤資訊
except Exception as e:
    print(e)
finally:
    aaa.close()

7 函式

7.1 函式的定義和常用操作

函式:函式是對程式邏輯進行結構化的一種程式設計方法。

函式的定義:

def 函式名稱():
	程式碼
	return 需要返回的內容

函式的呼叫:

函式名稱()

示例1:

原始未利用自定義函式的程式碼:

# 讀取人物
f = open('name.txt')
data = f.read()
print(data.split('|'))

# 讀取兵器的名稱
f2 = open('weapon.txt', encoding='utf-8')
# data2 = f2.read()
i = 1
for line in f2.readlines():
    if i % 2 == 1:
        print(line.strip('\n'))  # 通過strip('\n')將檔案末尾的換行符進行刪除
    i += 1

f3 = open('sanguo.txt', encoding='utf-8')
print(f3.read().replace('\n', ''))  # 讀取內容,並將文字中的換行替換成空格

可以利用函式進行實現:

def func(filename):
    print(open(filename).read())

print('test func')
func('name.txt')

示例2:

import re

def find_item(hero):
    with open('sanguo.txt', encoding='utf-8') as f:
        data = f.read().replace('\n', '')
        name_num = re.findall(hero, data)  # 這裡的findall是出現一次輸出一次
        print('主角 %s 出現了 %s 次' % (hero, len(name_num)))
    return name_num

# 讀取人物的資訊
name_dict = {}
with open('name.txt') as f:
    for line in f:
        names = line.split('|')
        for n in names:
            # print(n)
            name_num = find_item(n)
            name_dict[n] = name_num

執行結果:

7.2 函式的可變長操作

在函式中,需要按照順序進行引數傳入,如果想跳躍使用,則通過關鍵字引數來進行呼叫,示例如圖:

示例1:

def func(a, b, c):
    print('a = %s' % a)
    print('b = %s' % b)
    print('c = %s' % c)


func(1, c=3, b=2)

執行結果:

示例2:

#  取引數的個數
def howlong(first, *other):  # 通過加*的方式變為可變長引數,未加*的引數必須要進行填寫
    print(1 + len(other))


howlong(10, 20, 30)
howlong(2)

執行結果:

7.3 函式的變數作用域

當函式外部的變數賦值後,在函式內部使用相同名稱的變數時,會預設使用函式外部的變數;如果在函式內部對變數進行重新賦值,則會新建一個函式內部的變數,該變數的名稱和函式外部定義的變數名稱相同。

示例1:

var1 = 123
def func():
    print(var1)


func()

執行結果:

示例2:

var1 = 123

def func():
    var1 = 456
    print(var1)


func()
print(var1)

執行結果:

示例3:

var1 = 123

def func():
    # global var2 = 456  # 該行語法錯誤
    global var2
    var2 = 456
    print(var2)


func()
print(var1)
print(var2)

執行結果:

7.4 函式的迭代器和生成器

7.4.1 迭代器

示例:

list1 = (1, 2, 3)
it = iter(list1)
print(next(it))
print(next(it))
print(next(it))
print(next(it))  #這一行程式碼錯誤,已經迭代結束了

執行結果:

7.4.2 生成器

示例:

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:", res)

g = foo()
print("*" * 20)
print(next(g))
print("*" * 20)
print(next(g))

執行結果:

分析:
1.程式開始執行以後,因為foo函式中有yield關鍵字,所以foo函式並不會真的執行,而是先得到一個生成器g(相當於一個物件)
2.直到呼叫next方法,foo函式正式開始執行,先執行foo函式中的print方法,然後進入while迴圈
3.程式遇到yield關鍵字,然後把yield想想成return,return了一個4之後,程式停止,並沒有執行賦值給res操作,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print的結果,第二個是return出的結果)是執行print(next(g))的結果,
4.程式執行print(""20),輸出20個*
5.又開始執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛才那個next程式停止的地方開始執行的,也就是要執行res的賦值操作,這時候要注意,這個時候賦值操作的右邊是沒有值的(因為剛才那個是return出去了,並沒有給賦值操作的左邊傳引數),所以這個時候res賦值是None,所以接著下面的輸出就是res:None
6.程式會繼續在while裡執行,又一次碰到yield,這個時候同樣return 出4,然後程式停止,print函式輸出的4就是這次return出的4。
到這裡你可能就明白yield和return的關係和區別了,帶yield的函式是一個生成器,而不是一個函數了,這個生成器有一個函式就是next函式,next就相當於“下一步”生成哪個數,這一次的next開始的地方是接著上一次的next停止的地方執行的,所以呼叫next的時候,生成器並不會從foo函式的開始執行,只是接著上一步停止的地方開始,然後遇到yield後,return出要生成的數,此步就結束。

示例2:

def frange(star, stop, step):
    x = star
    while x < stop:
        yield x
        x += step


for i in frange(10, 20, 0.5):
    print(i)

執行結果:

7.5 lambda表示式

示例1:將lambda函式賦值給一個變數,通過這個變數間接呼叫該lambda函式。

通過傳統的方法定義函式:

def sum(x,y):
    return x+y
print(sum(5,9))

通過lambda的方法定義函式:

add = lambda x, y: x + y
print(add(5, 9))

示例2:將lambda函式作為引數傳遞給其他函式。部分Python內建函式接收函式作為引數。

通過傳統方式:

def odd(x):
    return x%2
temp = range(10)
show = filter(odd,temp)
print(list(show))   #[1, 3, 5, 7, 9]

通過lambda函式實現:

print(list(filter(lambda x: x%2,range(10))))    #[1, 3, 5, 7, 9]

此時lambda函式用於指定過濾列表元素的條件。

示例3:將lambda函式作為其他函式的返回值,返回給呼叫者。

函式的返回值也可以是函式。例如return lambda x, y: x+y返回一個加法函式。這時,lambda函式實際上是定義在某個函式內部的函式,稱之為巢狀函式,或者內部函式。對應的,將包含巢狀函式的函式稱之為外部函式。內部函式能夠訪問外部函式的區域性變數,這個特性是閉包(Closure)程式設計的基礎。

示例4:將lambda函式賦值給其他函式,從而將其他函式用該lambda函式替換。

例如:為了把標準庫time中的函式sleep的功能遮蔽(Mock),我們可以在程式初始化時呼叫:time.sleep=lambda x:None。這樣,在後續程式碼中呼叫time庫的sleep函式將不會執行原有的功能。例如,執行time.sleep(3)時,程式不會休眠3秒鐘,而是什麼都不做

示例5:將if...else語句縮減為單一的條件表示式,

語法expression1 if A else expression2

如果ATrue,條件表示式的結果為expression1,否則為expression2

def s(x):
    if x==1:
        return "yes"
    else:
        return "no"
print(s(0))
print(s(1))

使用lambda函式:

s = lambda x:"yes" if x==1 else "no"
print(s(0))
print(s(1))

7.6 Python內建函式

7.6.1filter函式

filter函式:

a = (1, 2, 3, 4, 5, 6, 7)
print(list(filter(lambda x: x > 2, a)))  # 需要將filter強制轉換成列表型別,否則系統不會執行

執行結果:

7.6.2 map函式

map函式:

a = [1, 2, 3]
print(list(map(lambda x: x + 1, a)))

執行結果:

7.6.3 reduce函式

reduce函式:

reduce函式不能直接使用,在終端中通過from functools import reduce命令匯入相應的函式包,然後才能使用reduce函式。

from functools import reduce

reduce(lambda x, y: x + y, [2, 3, 4], 1)  # 將數值1通過lambda函式分別對列表中的元素依次進行運算
# ((1+2)+3)+4

執行結果:

7.6.4 zip函式

zip函式:zip() 函式用於將可迭代的物件作為引數,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表。

示例1:

# zip((1, 2, 3), (4, 5, 6))
print((1, 2, 3), (4, 5, 6))
for i in zip((1, 2, 3), (4, 5, 6)):
    print(i)

執行結果:

示例2:

dicta = {'a': 'aaa', 'b': 'bbb'}
dictb = zip(dicta.values(), dicta.keys())
print(dict(dictb))

執行結果:

7.7 閉包

閉包概念:在一個內部函式中,對外部作用域的變數進行引用,(並且一般外部函式的返回值為內部函式),那麼內部函式就被認為是閉包。

示例1:

def sum(a):  # 內部函式
    def add(b):  # 內部函式
        print(a)
        print(b)
        return a + b  # 外部函式的變數 a 被內部函式引用稱為閉包

    return add


# add 函式名稱或函式的引用
# add() 函式的呼叫
# num1 = func()

num2 = sum(2)  # 該行程式碼返回的是一個函式
print(num2)
print(num2(5))
# print(type(num1))
# print(type(num2))

執行結果:

示例2:

def counter(a):
    cnt = [a]  # 列表

    def add_one():
        cnt[0] += 1
        return cnt[0]

    return add_one


num5 = counter(5)
print(num5())
print(num5())
print(num5())
print(num5())

num9 = counter(9)
print(num9())
print(num9())
print(num9())

執行結果:

示例3:

# 計算公式 a * x + b = y
def a_line(a, b):
    def arg_y(x):
        return a * x + b
    return arg_y


line1 = a_line(3, 5)
line2 = a_line(5, 10)
print(line1(10))
print(line2(20))

如果通過lambda來實現閉包,程式碼如下:

# 計算公式 a * x + b = y
def a_line(a, b):
    return lambda x: a * x + b


line1 = a_line(3, 5)
line2 = a_line(5, 10)
print(line1(10))
print(line2(20))

執行結果:

7.8 裝飾器

裝飾器的概念:裝飾器(Decorators)是 Python 的一個重要部分。簡單地說:他們是修改其他函式的功能的函式。他們有助於讓我們的程式碼更簡短,也更Pythonic(Python範兒)。

閉包和裝飾器的不同點:閉包傳入的是變數,內部引用的是變數;裝飾器傳入的是函式,內部引用的也是函式。

示例1:

import time

def timer(func):
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print('執行時間是 %s 秒' % (stop_time - start_time))
    return wrapper


@timer  # 裝飾函式
def i_can_sleep():  # 被裝飾函式
    time.sleep(3)  # 將暫停執行 3 秒這個函式傳遞給 timer ,對應timer中的函式為 func

i_can_sleep()  # 該行命令等同於 timer(i_can_sleep()) 或 a = timer(i_can_sleep())

執行過程:首先執行到i_can_sleep()時,會自動尋找i_can_sleep()這個函式,發現這個函式被裝飾,會跳轉到timer這個裝飾函式,將被裝飾函式i_can_sleep()作為func傳入,並執行wrapper()函式。

執行結果:

示例2:

def new_tips(argv):
    def tips(func):
        def nei(a, b):
            print('start %s  %s' % (argv, func.__name__)) # 通過func.__name__讀取函式名
            func(a, b)
            print('stop')
        return nei
    return tips


@new_tips('add_module')
def add(a, b):
    print(a + b)


@new_tips('sub_module')
def sub(a, b):
    print(a - b)


add(4, 5)
sub(9, 4)
print(add(4, 5))
print(sub(9, 4))

執行結果:

可以通過@裝飾器來進行重複進行呼叫。

7.9 上下文管理器

通過with來進行上下文管理:

傳統方式:

fd = open('name.txt')
try:
    for line in fd:
        print(line)
finally:
    fd.close()

通過with來進行上下文管理:

with open('name.txt') as f:
    for line in f:
        print(line)  # 當執行出現異常的時候,with會自動呼叫finally來關閉檔案

8 模組

模組是在程式碼量變得相當大之後,為了將需要重複使用的有組織的程式碼段放在一起,這部分程式碼可以附加到現有程式中,附加的過程叫做匯入(import)。

匯入模組的一般寫法:

  • import 模組名稱
  • from 模組名稱 import 方法名

示例:

import os  # 匯入 os 模組

import time  # 匯入 time 模組

import matplotlib as m  # 可以將 matplotlib 進行重新命名為 m

from time import sleep  # 匯入 time 模組中的 sleep 函式
sleep()  # 使用sleep函式,不推薦使用,可能出現自己定義的函式名稱和sleep重名

新建一個mymod.py檔案,並寫入如下程式碼:

def print_me():
    print('me')

新建一個mod_test.py檔案,並寫入如下程式碼:

import mymod
mymod.print_me()

執行結果:

9 面向物件程式設計

9.1 類與例項

示例1:

class Player():  # 定義一個類  類的名稱第一個字母大寫
    def __init__(self, name, hp, occu):
        self.__name = name  # self指的是例項化本身,即user1和user2,通過增加下劃線,對類進行封裝,該類的屬性可以不被訪問到
        self.hp = hp  # 在面向物件中,變數被成為屬性
        self.occu = occu

    def print_role(self):  # 定義一個方法/功能,在面向物件中,函式被稱為方法
        print('%s: %s %s ' % (self.__name, self.hp, self.occu))

    def updateName(self, newname):
        self.__name = newname


user1 = Player('tom', 100, 'war')  # 類的例項化
user2 = Player('jerry', 100, 'master')
print(1)
user1.print_role()
user2.print_role()

執行結果:

示例2:

class Player():  # 定義一個類  類的名稱第一個字母大寫
    def __init__(self, name, hp, occu):  # 類中第一個引數一定是self
        self.__name = name  # self指的是user1和user2,通過增加下劃線,對類進行封裝,該類的屬性可以不被訪問到
        self.hp = hp  # 在面向物件中,變數被成為屬性
        self.occu = occu

    def print_role(self):  # 定義一個方法/功能,在面向物件中,函式被稱為方法
        print('%s: %s %s ' % (self.__name, self.hp, self.occu))

    def updateName(self, newname):  # 類中第一個引數一定是self
        self.__name = newname

class New():
    # 下面通過單引號'xxx'或者"""xxx"""來對這個類進行說明,並不會報錯
    '定義怪物類'
    pass  #如果不確定這個類中寫什麼,可以暫時寫一個pass,編譯器不會報錯

user1 = Player('tom', 100, 'war')  # 類的例項化
user2 = Player('jerry', 100, 'master')
print(1)
user1.print_role()
user2.print_role()

user1.updateName('wilson')
user1.print_role()
user1.__name = ('aaa')    #無法更改類中屬性的值,因為已經被封裝,只有通過類本身的函式(方法)來更改
user1.print_role()

9.2 類的繼承

示例1:

class Monster():
    def __init__(self, hp=90):
        self.hp = hp  # 變數被稱為屬性

    def run(self):
        print('移動到某個位置')  # 函式被稱為方法

    def whoami(self):
        print('我是怪物父類')


class Animals(Monster):  # 在括號中寫繼承父類的名字  #Animals作為Monster的子類,使用Animals的時候就能夠呼叫Monster的hp和run
    """普通的怪物"""
    def __init__(self, hp=10):
        super().__init__(hp)  # 子類hp屬性和父類hp屬性屬於重複定義,父類中初始化了某些屬性,子類不用重複初始化該子類


class Boss(Monster):
    """Boss類怪物"""
    def __init__(self, hp=1000):
        self.hp = hp

    def whoami(self):
        print('我是怪物我怕誰haha')


a1 = Monster(100)  # 會直接賦值替換原來__init__初始化的值
print('a1:')
print(a1.hp)
print(a1.run())
a2 = Animals(1)  # a2
print('a2:')
print(a2.hp)
print(a2.run())  # 此時可以看出a2可以繼承父類方法
print(a2.whoami())  # 此時可以看出a2可以繼承父類方法

print('a3:')
a3 = Boss(800)
print(a3.hp)
a3.whoami()  # 子類的繼承中如果有重名的方法,會替換父類中的方法

print('a1的型別 %s ' % type(a1))
print('a2的型別 %s ' % type(a2))
print('a3的型別 %s ' % type(a3))

print(isinstance(a2, Monster))  # isinstance可以用來判斷a2是否為Monster的子類

執行結果:

示例2:

class Testwith():
    def __enter__(self):  # 類初始化的時候會呼叫這一行
        print('run')

    def __exit__(self, exc_type, exc_val, exc_tb):  # 類結束的時候會呼叫這一行
        if exc_tb is None:  # 沒有異常,則exc_tb值為空
            print('正常結束')
        else:
            print('Has error %s ' % exc_tb)


with Testwith():
    print('Test is running')
    raise NameError('testNameError')  # 用raise丟擲異常

執行結果:

10 多執行緒程式設計

示例1:

import threading
import time
from threading import current_thread

def myThread(arg1, arg2):
    print(current_thread().name, 'start')
    print('%s %s' % (arg1, arg2))
    time.sleep(1)
    print(current_thread().name, 'stop')

print('執行開始')
for i in range(1, 6):
    t1 = threading.Thread(target=myThread, args=(i, i + 1))
    t1.start()  # 加上start方法之後多執行緒才能執行起來
print('執行結束')
print(current_thread().name, 'end')

執行分析:主執行緒執行結束才會執行

執行結果1:

執行結果2:

如果執行的多執行緒中某些執行緒先結束,希望該執行緒等待其他執行緒全部結束後再繼續執行,則通過join的方法來實現。

示例2:

import threading
from threading import current_thread

class Mythread(threading.Thread):  # 使用Thread方法的名稱,不是引用
    def run(self):
        print(current_thread().name, 'start')
        print('run')
        print(current_thread().name, 'stop')

t1 = Mythread()
t1.start()
t1.join()  #為了使Thread先結束,主執行緒後結束,採用join的方法

print(current_thread().name, 'end')

執行結果:

經典的生產者和消費者的問題:

示例:

from threading import Thread, current_thread
import time
import random
from queue import Queue

queue = Queue(5)  # 定義佇列的長度為 5


class ProducerThread(Thread):
    def run(self):
        name = current_thread().name
        nums = range(100)
        global queue
        while True:
            num = random.choice(nums)
            queue.put(num)  # 向佇列中加入資料
            print('生產者 %s 生產了資料 %s' % (name, num))
            t = random.randint(1, 3)
            time.sleep(t)
            print('生產者 %s 睡眠了 %s 秒' % (name, t))


class ConsumerThread(Thread):
    def run(self):
        name = current_thread().name
        global queue
        while True:
            num = queue.get()  # 根據加入的資料的順序進行讀取
            queue.task_done()  # 沒有用join等待,因為task_done這個方法中已經封裝好了執行緒等待和執行緒同步的程式碼,可以直接使用
            print('消費者 %s 消耗了資料 %s' % (name, num))
            t = random.randint(1, 5)
            time.sleep(t)
            print('消費者 %s 睡眠了 %s 秒' % (name, t))


p1 = ProducerThread(name='p1')
p1.start()
p2 = ProducerThread(name='p2')
p2.start()
p3 = ProducerThread(name='p3')
p3.start()

c1 = ConsumerThread(name='c1')
c1.start()
c2 = ConsumerThread(name='c2')
c2.start()
c3 = ConsumerThread(name='c3')
c3.start()
c4 = ConsumerThread(name='c4')
c4.start()

執行分析:如果生產者多餘消費者,當佇列中存放的資料滿了之後,則生產者將不再生產資料,只要當消耗著消耗部分後,佇列中有多餘位置,才會產生資料。

11 標準庫

Python官方文件對應地址:https://docs.python.org/3/library/index.html

Python常用的標準庫:

  • Built-in Types
  • Text Processing Services
  • Data Types
  • Generic Operating System Services
  • Internet Data Handling
  • Development Tools
  • Debugging and Profiling

11.1 正則表示式庫 - re

11.1.1 正則表示式元字元

示例1:匹配相同字元

import re

p = re.compile('a')
print(p.match('a'))
print(p.match('b'))

執行結果:

示例2:.可以匹配所有任意的單個字元

import re

d = re.compile('.')
print(d.match('c'))
print(d.match('t'))

執行結果:

示例3:^以什麼作為開頭,從開頭進行搜尋

示例4:$以什麼作為結尾,從後面往前面進行匹配,比如以d = re.compile('jpg$')表示以jpg作為結尾,來進行檢索。

示例5:*表示匹配前面的字元出現0次到多次

import re

b = re.compile('ca*t')
print(b.match('cat'))
print(b.match('caat'))

執行結果:

示例6:?代表字元出現0次或1次

import re

b = re.compile('c?t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caaat'))

執行結果:

示例7:{內容}表示前面字元出現指定次數

import re

b = re.compile('ca{4,6}t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caaaat'))
print(b.match('caaaaat'))
print(b.match('caaaaaaat'))

執行結果:

示例8:[內容]表示匹配方括號中的任意一個字元

import re

b = re.compile('ca[abcd]t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caabcdt'))
print(b.match('cact'))
print(b.match('cabt'))

執行結果:

示例9:\d用來匹配多個數字字元[0-9](多個[0-9]也可以用[0-9]+表示)

示例10:\D用來匹配非數字字元

示例11:\s表示匹配的是字串

示例12:.*?表示不匹配貪婪模式,例如下面的內容

<img   /img>
<img   /img>

如果使用.*?不匹配貪婪模式,則只會匹配第一行,不會匹配所有的行。

11.1.2 正則表示式分組功能

示例1:

import re

b = re.compile('ca...t')
print(b.match('cat'))
print(b.match('caabct'))
print(b.match('cact'))

print('**********')
c = re.compile('ca.{2}t')
print(c.match('cat'))
print(c.match('cact'))
print(c.match('cacbt'))

執行結果:

11.1.3 正則表示式中match和search的區別

示例1:

import re

b = re.compile(r'(\d+)-(\d+)-(\d+)')  # 在前面加上r代表後面的內容不進行轉義
print(b.match('2022-05-30'))
print(b.match('2022-05-30').group(1))
print(b.match('2022-05-30').group(2))
print(b.match('2022-05-30').groups())
(year, month, day) = b.match('2022-05-30').groups()
print('year = %s' % year)
print('month = %s' % month)
print('day = %s' % day)

執行結果:

示例2:

import re

b = re.compile(r'(\d+)-(\d+)-(\d+)')  # 在前面加上r代表後面的內容不進行轉義
print(b.search('aa2022-05-30bbb'))
print(b.search('aa2022-05-30bbb').group())  # search用來搜尋指定字串
print(b.search('aa2022-05-30bbb').group(1))
print(b.search('aa2022-05-30bbb').group(2))
print(b.search('aa2022-05-30bbb').groups())
(year, month, day) = b.search('aa2022-05-30bbb').groups()
print('year = %s' % year)
print('month = %s' % month)
print('day = %s' % day)

執行結果:

11.1.4 正則表示式替換函式sub()

示例1:

import re

phone = '123-456-798 # 這是電話號碼'
# 用r表示後面的字元不進行轉義,#表示匹配#號,#.*表示匹配#後面所有內容,*是多個的意思,$表示一直到結尾
# sub('原來需要替換的內容','需要替換的新內容',字串名字)
p2 = re.sub(r'#.*$', '', phone)
print(p2)
p3 = re.sub(r'\D', '', p2)  # \D 表示選擇非數字的部分
print(p3)

執行結果:

11.2 日期與時間函式庫

time模組多數是用來檢視日期和時間

示例1:

import time

print(time.time())  # 顯示的是1970年1月1日到現在的秒數
print(time.localtime())
print(time.strftime('%Y-%m-%d %H:%M:%S'))
print(time.strftime('%Y%m%d'))

執行結果:

datetime多用於時間的修改

示例2:

import datetime
print(datetime.datetime.now())
# 如果想獲取十分鐘以後的時間,可以通過類似加減法的方式來進行計算
newtime = datetime.timedelta(minutes=10)  # timedelta為偏移時間
print(datetime.datetime.now() + newtime)

one_day = datetime.datetime(2000, 5, 27)
print(one_day)
new_date = datetime.timedelta(days=10)
print(one_day + new_date)

執行結果:

11.3 數學相關庫

數學相關的庫為:Numeric and Mathmatical Modules

示例:

import random

print(random.randint(1, 5))  # 產生1到5的整數(包括1和5)
print(random.choice(['aa', 'bb', 'cc']))

執行結果:

11.4 對檔案和資料夾操作庫

在Linux的終端中,常用操作命令:

pwd     #返回當前的地址
cd ..   # 訪問上一級目錄
cd /tmp   #訪問根目錄下的tmp資料夾,這個進入方式為絕對路徑
cd ./tmp   #訪問當前目錄的下一級目錄,即進入tmp資料夾,這個進入方式為相對路徑
mkdir /tmp/a    #建立資料夾
mkdir -p /tmp/a    #如果不存在相應的檔案,通過
rmdir g   #如果當前終端在g資料夾的上一級目錄中,可以通過此命令來刪除g資料夾
rm -rf /tmp/a  #如果某個目錄中存在子目錄,可以通過此命令將a資料夾和a資料夾下的所有檔案進行刪除

11.4.1 資料夾操作庫-os.path

通過資料夾操作庫對檔案和資料夾進行操作

示例:

import os
from os import path

print(os.path.abspath('.'))  # 通過 . 來獲取絕對路徑
print(os.path.abspath('..'))  # 通過 .. 來獲取上一級的絕對路徑
print(os.path.exists('/users'))  # 判斷根目錄下的users資料夾是否存在,如果存在返回True,不存在返回False
print(os.path.isfile('/Code/Code_py'))  # 判斷Code_py是否為檔案
print(os.path.isdir('/Code/Code_py'))  # 判斷Code_py是否為檔案

print(os.path.join('/tmp/a/', 'b/c'))  # 將兩個路徑進行拼接

執行結果:

11.4.2 資料夾操作庫-pathlib.Path

示例:

from pathlib import Path
p = Path('/Code/Code_py')
print(p.resolve())  # 通過此方法可以得到相對路徑的絕對路徑
print(p.is_dir())

q = Path('/tmp/a')
# parents設為True,當q對應的目錄不存在,則建立目錄
# parents設為False,當q對應的目錄不存在,則不建立目錄
Path.mkdir(q,parents=True)

執行結果:

可以看到該資料夾已經建立

12 機器學習

12.1 numpy庫

numpy庫:用於高效能科學計算和資料分析,是常用的高階資料分析庫的基礎包,用numpy庫的執行效率比python自身的執行效率更高。

需要在終端中通過pip3 install numpy命令來安裝numpy庫,執行效果:

示例1:

import numpy as np

arr1 = np.array([2, 3, 4])
print(arr1)
print(arr1.dtype)

arr2 = np.array([1.2, 2.3, 3.4])
print(arr2)
print(arr2.dtype)

#可以有多種資料型別:int8 int16 int32 int64等  numpy可以根據輸入的資料型別自動進行轉換
print(arr1 + arr2)

執行結果:

示例2:

import numpy as np

arr2 = np.array([1.2, 2.3, 3.4])

print(arr2 * 10)
data = ((1, 2, 3), (4, 5, 6))
print(data)
arr3 = np.array((data))  # 將data轉為二維矩陣
print(arr3)
print(arr3.dtype)

print('np:zeros, ones和empty:')
print(np.zeros(10))
print(np.zeros((3, 5)))
print(np.ones((4,6)))
print(np.empty((2,3,2)))

執行結果:

示例3:

import numpy as np

arr4 = np.arange(10)
print(arr4[5:8])
arr4[5:8] = 10
print(arr4)
arr_slice = arr4[5:8].copy()  # 對原有資料進行切片(部分賦值)給arr_slice
print(arr_slice)
arr_slice[:] = 15
print(arr_slice)
print(arr4)

執行結果:

12.2 pandas庫

pandas是用來資料預處理、資料清洗非常重要的庫。

需要在終端中通過pip3 install pandas命令來安裝pandas庫,執行效果:

Series可以看作一維的字典,dataframe可以看作二維的字典。

12.2.1 Series資料結構

示例1:

from pandas import Series, DataFrame
import pandas as pd

# pandas會將你的資料自動進行資料排列或者按照自定義的方式進行排列顯示,避免資料沒有對齊,處理資料出現失誤
# pandas可以很靈活處理缺失的資料,也可以填充想要的值

obj = Series([4, 5, 6, -7])
print(obj)
print(obj.index)
print(obj.values)

執行結果:

示例2:

from pandas import Series, DataFrame
import pandas as pd

obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'c', 'a'])
print(obj2)

obj2['c'] = 6
print(obj2)
print('a' in obj2)

執行結果:

示例3:

from pandas import Series, DataFrame
import pandas as pd

sdata = {
    'beijing': 35000,
    'shanghai': 71000,
    'guangzhou': 16000,
    'shenzhen': 5000}
obj3 = Series(sdata)
print(obj3)

obj3.index = ['bj', 'gz', 'sh', 'sz']
print(obj3)

執行結果:

12.2.2 Dataframe資料結構

示例1:

from pandas import Series, DataFrame
import pandas as pd

data = {
    'city': [
        'shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'], 'year': [
            2016, 2017, 2018, 2017, 2018], 'pop': [
                1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
print(frame)
frame2 = DataFrame(data, columns=['year', 'city', 'pop'])
print(frame2)
print(frame2['city'])
print('***************')
print('year:')
print(frame2.year)

執行結果:

示例2:

from pandas import Series, DataFrame
import pandas as pd

data = {
    'city': [
        'shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'], 'year': [
            2016, 2017, 2018, 2017, 2018], 'pop': [
                1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
frame2 = DataFrame(data, columns=['year', 'city', 'pop'])

frame2['new'] = 100
print(frame2)  # 增加一個新的列
frame2['cap'] = frame2.city == 'beijing'
print(frame2)

執行結果:

示例3:

from pandas import Series, DataFrame
import pandas as pd

pop = {'beijing': {2008: 1.5, 2009: 2.0},
       'shanghai': {2008: 2.0, 2009: 3.6}}
frame3 = DataFrame(pop)
print(frame3)
print(frame3.T)

執行結果:

示例4:

from pandas import Series, DataFrame
import pandas as pd

obj4 = Series([4.5, 7.2, -5.3, 3.6], index=['b', 'c', 'd', 'a'])
obj5 = obj4.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
print(obj5)

obj6 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
print(obj6.reindex(range(6), method='ffill'))  #如果用後面的值進行填充,用 bfill

執行結果:

示例5:

from pandas import Series, DataFrame
import pandas as pd

from numpy import nan as NA
data = Series([1, NA, 2])
print(data)
print(data.dropna())  # 刪除NA對應的索引

執行結果:

示例6:

from pandas import Series, DataFrame
import pandas as pd
from numpy import nan as NA

data2 = DataFrame([[1., 6.5, 3], [1., NA, NA], [NA, NA, NA]])
print('下面展示的是刪除一整行全為NAN的這一行')
print(data2.dropna(how='all'))

data2[4] = NA
print('下面展示的是刪除一整行全為NAN的這一列:')
print(data2)
print(data2.dropna(axis=1, how='all'))
data2.fillna(0)
print(('******'))
print(data2)
data2.fillna(0, inplace=True)
print(data2.fillna(0, inplace=True))
print(data2)

執行結果:

12.2.3 層次化索引

pandas支援多層次索引

示例1:

from pandas import Series, DataFrame
import numpy as np

data3 = Series(np.random.random(10), index=[
               ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print(data3)
print('輸出單個索引:')
print(data3['b'])
print('輸出多個索引:')
print(data3['b':'d'])

執行結果:

示例2:

from pandas import Series, DataFrame
import numpy as np

data3 = Series(np.random.random(10), index=[
               ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print('將Series一維資料轉換成DataFrame二維資料:')
print(data3.unstack())
print('DataFrame二維資料轉換成將Series一維資料:')
print(data3.unstack().stack())

執行結果:

12.3 matplotlib庫

matplotlib庫主要用於繪圖。

需要在終端中通過pip3 install matplotlib命令來安裝matplotlib庫。

示例:

import matplotlib .pyplot as plt
# 繪製選單的曲線
plt.plot([1,3,5],[4,8,10])
plt.show()

執行結果:

示例2:

import matplotlib .pyplot as plt
import numpy as np

x = np.linspace(-np.pi, np.pi, 100)  # x軸的定義域為-3.14 到3.14,中間間隔100個元素
plt.plot(x, np.sin(x))
# 顯示所畫的圖
plt.show()

執行結果:

示例3:

import matplotlib .pyplot as plt
import numpy as np

x = np.linspace(-np.pi, np.pi, 100)  # x軸的定義域為-3.14 到3.14,中間間隔100個元素
plt.figure(1, dpi=50)  # 建立圖表1
for i in range(1, 5):
    plt.plot(x, np.sin(x / i))
# 顯示所畫的圖
plt.show()

執行結果:

示例4:

import matplotlib .pyplot as plt

plt.figure(1, dpi=50)  # 建立圖表1,dpi代表圖片精細度,dpi越大檔案越大,雜誌要dpi300以上
data = [1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 4]
plt.hist(data)  # 只要傳入資料,直方圖就會統計資料出現的次數
plt.show()

執行結果:

示例4:

import matplotlib .pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x
fig = plt.figure()
plt.scatter(x,y,c = 'r',marker='o')  # c = 'r'表示散點的顏色為紅色,marker表示指定散點形狀為圓形
plt.show()

執行結果:

12.4 seaborn庫

需要在終端中通過pip3 install seaborn命令來安裝seaborn庫。

12.5 tensorflow庫

需要在終端中通過pip3 install tensorflow命令來安裝tensorflow庫。

13 爬蟲

常用的網路庫包括:

  • urllib庫:資料收集和下載的庫
  • requests庫:資料收集和下載的庫
  • BeautifulSoup庫:格式處理
  • http協議常用庫
  • http協議常用庫
  • xml格式處理庫

httpbin.org是測試http協議的網站,可以通過它測試http功能。

示例1:

from urllib import request

url = 'http://www.baidu.com'
response = request.urlopen(url, timeout=1)
print(response.read().decode('utf-8'))  # 將讀取的網頁通過utf-8進行讀取,utf-8是漢字編碼的一種方式

執行結果:

示例2:

可以通過輸入httpbin.org/get?a=123&b=456來告訴伺服器a的值為123,b的值為456。

通過上面的get來往伺服器傳遞資料,有傳輸資料大小的限制。還有另一種向伺服器傳遞資料的限制,向伺服器提供密碼的時候會用post來進行提交。

示例3:

from urllib import parse
from urllib import request

data = bytes(parse.urlencode({'word': 'hello'}), encoding='utf-8')  # 對資料進行封裝
print(data)

print('***********************')
response = request.urlopen('http://httpbin.org/post', data=data)  # 通過urlopen開啟網頁,同時指定傳輸的資料
print(response.read().decode('utf-8'))

print('***********************')
response2 = request.urlopen('http://httpbin.org/get', timeout=1)  # 強烈建議寫timeout,否則會出現卡死的情況
print(response2.read())

執行結果:

示例4:

from urllib import parse
from urllib import request

import socket
import urllib

try:
    response3 = request.urlopen('http://httpbin.org/get', timeout=0.1)  # 強烈建議寫timeout,否則會出現卡死的情況
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

執行結果:

示例5:用headers來偽裝頭部

from urllib import  request,parse
url = 'http://httpbin.org/post'

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
    "X-Amzn-Trace-Id": "Root=1-623e6011-127adb2c4d8dfd857e37a791"
}
dict = {
    'name':'value'
}

data = bytes(parse.urlencode(dict), encoding='utf-8')  # 對字典重新編碼,即將其變為網頁的位元組形式進行封裝
req = request.Request(url=url,data=data,headers=headers,method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

執行結果:

需要在終端中通過pip3 install requests命令來安裝requests庫。

示例6:

# get請求
import requests
url = 'http://httpbin.org/get'
data = {'key': 'value', 'abc': 'xyz'}
# .get是使用get方式請求url,字典型別的data不用機型額外處理
response = requests.get(url, data)
print(response.text)


# post請求
url = 'http://httpbin.org/post'
data = {'key': 'value', 'abc': 'xyz'}
# .post表示為post方法
response = requests.post(url, data)
# 返回型別為json格式
print(response.json())

執行結果:

示例7:

import requests
import re

content = requests.get('http://www.cnu.cc/discoveryPage/hot-111').text
print(content)

# 這是網頁中對應的資訊,通過正則表示式提取
# <div class ="grid-item work-thumbnail>
# <a href="http://www.cnu.cc//works/244938" class ="thumbnail" target="_blank">
# <div class ="title">Fashion kids | 復古同年< / div>
# <div class ="author"> Lynride < / div>
pattern = re.compile(r'<a href="(.*?)".*?title">(.*?)</div>', re.S)
results = re.findall(pattern, content)
print(results)

for result in results:
    url, name = result
    print(url, re.sub('\\s', '', name))

執行結果:部分執行結果如下

需要在終端中通過pip3 install bs4命令來安裝BeautifulSoup庫。

示例8:

from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

soup = BeautifulSoup(html_doc, 'lxml')  # 選用html解析器
# print(soup)
print(soup.prettify())  # 當格式比較混亂的時候,通過此方法可以對其格式化處理
print('*********title:')
print(soup.title)
print(soup.title.string)
print(soup.title.parent.name)
print('*********head:')
print(soup.head)
print('*********body:')
print(soup.body)
print('*********p:')
print(soup.p)  # 找到p標籤
print(soup.p['class'])
print('*********a:')
print(soup.a)  # 找到第一個a標籤
print(soup.a['class'])
print('*********all p:')
print(soup.find_all('p'))
print('*********all a:')
print(soup.find_all('a'))
print('*********link3:')
print(soup.find(id="link3"))

print('*********href:')
for link in soup.find_all('a'):
    print(link.get('href'))
print('get_text:')
print(soup.get_text())

執行結果: