日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

Python语法--Mooc七月

發(fā)布時間:2024/1/8 python 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python语法--Mooc七月 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考資料備用:
python ABC
3.8.2Documentation
python cookbook 3rd
pip安裝超時解決辦法

vscode小技巧

  • 打開命令窗口:Ctrl+`
  • 注釋:單行 – Ctrl+/,多行 – Shift+Alt+A
  • cmd:cls清屏
  • Ctrl + Shift + O:快速定位函數(shù)

目錄速查

Python入門導(dǎo)學(xué)
Python基本類型:數(shù)字,字符串
組:列表,元組,集合,字典
變量與運算符
分支、循環(huán)、條件和枚舉
包、模塊、類
函數(shù)
面向?qū)ο?#xff1a;類,實例,方法,繼承
正則表達(dá)式和JSON
枚舉類型,閉包
匿名函數(shù)、高階函數(shù)、裝飾器
爬蟲實戰(zhàn)
Python雜記

Python入門導(dǎo)學(xué)

返回

特點

  • 簡潔;豐富的標(biāo)準(zhǔn)庫和第三方庫(電子郵件、GUI);面向?qū)ο?#43;函數(shù)式編程;易于上手,難于精通;既有動態(tài)腳本的特性,又有面向?qū)ο蟮奶匦浴?/li>
  • 豆瓣、知乎
  • Simple is better than complex.
    Now is better than never. Although never is often better than an right now.
  • 缺點:慢
    編譯型語言(C、C++)–運行效率
    解釋型語言(Javascript,Python)–開發(fā)效率

一個經(jīng)典誤區(qū):編程 = web編程?

  • 世界上不是只有網(wǎng)站,還有很多問題需要編程來解決。
  • web是基礎(chǔ)–爬蟲、數(shù)據(jù)服務(wù)提供、數(shù)據(jù)分析。
  • 互聯(lián)網(wǎng)時代,有網(wǎng)絡(luò)的地方就需要web。
  • web編程確實是最好的語言實踐–業(yè)務(wù)邏輯思考能力、寬廣的知識面。

Python能做什么

  • 爬蟲
  • 大數(shù)據(jù)與數(shù)據(jù)分析(Spark)
  • 自動化運維與自動化測試
  • web開發(fā):Flask,Django
  • 機器學(xué)習(xí):Tensor Flow(谷歌)
  • 膠水語言:能夠把其他語言制作的各種模塊(尤其是C/C++)輕松地聯(lián)結(jié)在一起

正確打開方式:遇到問題時,隨手拿起Python寫個工具

什么是寫代碼&Python的基本類型

返回

什么是代碼,什么是寫代碼

  • 代碼: 現(xiàn)實世界事物在計算機世界中的映射
  • 寫代碼: 將現(xiàn)實世界中的事物用計算機語言來描述

數(shù)字

整型與浮點型

  • 整數(shù):int
    其他語言有short,int,long
  • 浮點數(shù):float
    其他語言有單雙精度之分,Python沒有

type(2/2)是float(1.0),type(2//2)是int(1)
*雙斜杠是“整除”

10、2、8、16進(jìn)制&表示&轉(zhuǎn)換

  • 其他進(jìn)制:60s = 1min
  • 2進(jìn)制:0b10,直接在IDLE回車就會返回2
    8進(jìn)制:0o10 = 8
    16進(jìn)制:0x10 = 16
  • bin():將其他進(jìn)制轉(zhuǎn)換成2進(jìn)制
    oct():將其他進(jìn)制轉(zhuǎn)換成8進(jìn)制
    hex():將其他進(jìn)制轉(zhuǎn)換成16進(jìn)制
    int():將其他進(jìn)制轉(zhuǎn)換成10進(jìn)制

布爾類型和復(fù)數(shù)(屬于數(shù)字分類)

  • bool:表示真、假
    True/False,要大寫
    只要非 0/空串/空列表/None,就都是True
  • complex:復(fù)數(shù)(36j)
    抓大放小,抓住重點深入

字符串str

單雙引號

  • 單引號和雙引號–成對出現(xiàn)
    "let's go",'let\'s go'

多行字符串

  • 一行79,回車字符\n會讀進(jìn)字符串中
''' hello world hello world ''' """ hello world hello world """
  • IDLE寫'\n'輸出還是'\n',不換行
    print("""hello world\nhello world\n""")會輸出換行
  • 單引號換行:
'hello\ world'

輸出'helloworld'

轉(zhuǎn)義字符–特殊的字符

  • 表示無法“看見”的字符
  • 與本身語法有沖突的字符
  • \n換行
    \r回車:光標(biāo)回到本行首位置,不會換行
    \t橫向制表符:TAB
    \'單引號

原始字符串

  • 字符串前加r/R,原始字符串–所看即所得。
  • 'let's go'無法通過加r解決–引號要成對出現(xiàn)

字符串運算

  • +:拼接
    *數(shù)字:重復(fù)數(shù)字倍
  • 獲取單個字符:“字符串”[i],負(fù)數(shù)從后往前數(shù)
    獲取一段字符:步長
    'hello world'[0:4]輸出'hell',要讀到字符下一位
    'hello world'[0:-1]輸出'hello worl'
  • 怎么輸出world?
    "hello world"[6:],默認(rèn)取字符串最后一位
    "hello world"[-5:],后往前數(shù)第5位,到末尾

“組”的概念與定義

返回

列表list

定義

列表內(nèi)部可以存放不同類型元素
列表內(nèi)部可以嵌套列表

基本操作

  • 取元素
["新月打擊","蒼白之瀑","月之降臨","月神沖刺"][0] '新月打擊' #返回的是元素 ["新月打擊","蒼白之瀑","月之降臨","月神沖刺"][-1:] ['月神沖刺'] #返回的是列表
  • 合并列表:+
  • *3:把列表內(nèi)元素重復(fù)三次

元組tuple

  • 同列表
  • type(('hello'))返回值str:為什么只有一個元素的元組是元素的類型?
    答:()內(nèi)只有一個元素,python優(yōu)先認(rèn)為()是數(shù)學(xué)運算符,返回數(shù)學(xué)運(比如(1))。
    表示只有一個元素的元組:(1,)
    表示一個元素都沒有的空元組:()
    type([1])返回值是list

序列總結(jié)

  • 序號
  • 切片
    "hello world"[0:8:2]返回'hlow–在0-7的切片內(nèi)隔1取元素?
  • +,*
  • 元素是否在序列中:in,not in,返回bool值
    3 in [1,2,3,4,5]返回True
  • len(),max(),min():返回序列長度、最大值、最小值
    max、min不支持不同類型元素比較
  • ord()返回單個字符的ASC碼(字符串不行)

集合set

  • 最大的特點——無序
    {1,2,3,4,5}不支持序號、切片
  • 不重復(fù)
    {1,1,1,2,2,3,4,5}返回{1,2,3,4,5}
  • len()
    in、not in
  • {1,2,3,4,5,6} - {3,4}:兩個集合取差集
    {1,2,3,4,5,6} & {3,4}:兩個集合取交集
    {1,2,3,4,5,6} | {3,4,7}:兩個集合取并集
  • 怎么定義空的集合?
    type({})返回dict類型 – 不可用
    type(set())返回set類型 – 正確操作

字典dict

  • 很多的key和value,set的延生而不是序列的
    {key1:value, key2:value, ……}
  • 最常用操作:通過key得到/訪問value
  • key值不可重復(fù)
{'Q':"新月打擊",'W':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}['Q'] '新月打擊' {'Q':"新月打擊",'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}['Q'] '蒼白之瀑' {'Q':"新月打擊",'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"} {'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}
  • value類型無限制,可以也是一個字典
    key必須是不可變的類型 – 字符串和元組不可變,列表可變

變量與運算符

返回

變量

什么是變量

  • 名字:起名字要有意義 – 命名可讀性要強,多查單詞
  • =:賦值符號

命名規(guī)則

  • 字母、數(shù)字、下劃線
  • 首位不能是數(shù)字
  • 系統(tǒng)關(guān)鍵字(保留關(guān)鍵字)不能用在變量名中
    非保留的也盡量不要用,血和淚的教訓(xùn)。
type = 1 type(1) #報錯,此時等價于1(1)

值類型與引用類型

a = 1 b = a a = 3 #a指向了新的int(3) print(b) #1a = [1,2,3,4,5] b = a a[0] = '1' #a沒有指向新的list,而是改變原來的list print(b) #['1',2,3,4,5]
  • 值類型:不可改變
    int、str、tuple
    引用類型:可改變
    list、set、dict
#str不可變,id()得到地址,發(fā)現(xiàn)前后地址變了,說明不是在原地址上修改 b = 'hello' b = b + 'python' #生成新的字符串,再賦值給b print(b) #hellopython
  • list和tuple:
    元組不可修改,能用元組就用元組 – 代碼穩(wěn)定性考慮
a = (1,2,3,[1,2,['a','b','c']]) a[2] = '3' #不可改變,報錯 a[3][2][1] = '4' #可以改變,變?yōu)?1,2,3,[1,2,['a','4','c']])

運算符

算術(shù)運算符

+,-,*,/,//整除,%,**指數(shù)(2**5 = 32)

賦值運算符

  • 先做運算再賦值
  • python中沒有自增自減運算

比較運算符

  • 返回一個bool值

邏輯運算符

  • 與、或、非
  • int,float中0被認(rèn)為是False
    字符串中空字符串""是False
    列表中空的列表[]被認(rèn)為是False
  • and 和 or 的返回值 – 最后一個讀到的內(nèi)容
    1 and 2返回2,2 and 1返回1 – 讀到第二個數(shù)字才能判斷
    1 or 2返回1 – 讀到第一個1的時候就能判斷了

成員運算符

  • in,not in
  • 字典類型判斷的是key

身份運算符

  • is,is not– 兩個變量的身份是否相等
a = 1 b = 1.0 a == b #True a is b #False
  • id()查看他們的地址,地址相同身份相同 – is比較的是地址
a = {1,2,3} b = {2,1,3} a == b #True, set無序 a is b #False, 地址不同

判斷變量的值、身份、類型 – 對象3特征

  • ==值
    is身份
    isinstance(a, int)類型
  • isinstance(a, (int, str, float)) a是否是元組里三個類型中的一個,是返回True,否返回False

位運算符

b = 3 bin(b) #'0b11',3 bin(~b) #'-0b100',前面取負(fù)末位+1,-4 a = 2 bin(a) #'0b10' bin(a<<1) #'0b100' bin(a>>3) #'0b0'

分支、循環(huán)、條件和枚舉

返回

表達(dá)式

什么是表達(dá)式

表達(dá)式是運算符和操作數(shù)組成的序列

表達(dá)式優(yōu)先級

  • 一般右結(jié)合,出現(xiàn)=左結(jié)合,與運算符優(yōu)先級無關(guān)
  • 運算符優(yōu)先級最高,然后是比較,邏輯運算符最低:not > and > or
  • 加輔助括號可以改變運算順序

流程控制語句

條件控制

if d:a = input() #讀入的是字符串pass #空語句,占位語句 elif:pass else:pass

pylint規(guī)范

  • python中實際沒有常量,用大寫
  • 每個模塊開頭一段注釋,說明
  • tab 四個空格、切換到下一個代碼編輯區(qū)域
  • python沒有switch
    elif代替,或者字典處理
  • a,b不同時為False:a or b

循環(huán)

while的循環(huán)場景

  • 遞歸
counter = 1 while counter <= 10:counter += 1print(counter) else:print('EOF') #循環(huán)結(jié)束的時候執(zhí)行else

for

for target_list in expression_list:pass else:pass #列表全部打完以后執(zhí)行else,強制break結(jié)束時不會執(zhí)行else
  • range
for x in range(0, 10, 2): #范圍,步長pass for x in range(10, 0, -2):printf(x, end=' | ')一定要用for嗎? a = [1,2,3,4,5,6,7,8] for i in range(0, len(a), 2):print(a[i], end=' | ') b = a[0:len(a):2] print(b)

python的組織結(jié)構(gòu)-包、模塊、類

返回

  • 包(文件夾,包含__init__.py),模塊,類(用類把函數(shù)、變量組織起來)
    包.模塊seven.c4,子包
  • __init__.py的模塊名就是包的名字

導(dǎo)入

import c7 #同級,導(dǎo)入模塊 print(c7.a)import t.c7 #子包中 print(t.c7.a)from t.c7 import a, def #導(dǎo)入變量、函數(shù) print(a)from t import c7 #導(dǎo)入模塊 print(c7.a)from t.c7 import * #導(dǎo)入所有變量和函數(shù),能不用就不用 __all__ = ['a', 'c'] #在模塊開頭,改變*關(guān)于全部的定義 #模塊的內(nèi)置屬性#末尾加反斜杠可以換行, ()也可以換行 from c7 import a, b\ c from c7 import (a, b c)

init.py

  • 導(dǎo)入包時自動運行:
    無論是導(dǎo)入包還是導(dǎo)入包下面的模塊,都會自動運行__init__.py
  • 在__init__.py內(nèi)設(shè)置__all__可以控制*時導(dǎo)入的包內(nèi)模塊
  • 批量導(dǎo)入包
  • 注意點:
    ① 包和模塊不會被重復(fù)導(dǎo)入
    ② 避免循環(huán)導(dǎo)入
    ③ python導(dǎo)入模塊時會執(zhí)行所導(dǎo)入模塊的代碼

模塊內(nèi)置變量

  • dir()返回當(dāng)前模塊的變量列表
    dir(sys)返回指定模塊sys的變量列表
  • 錯誤信息:堆棧信息(路徑)+詳細(xì)信息(原因)
  • __doc__存放模塊注釋信息
    __file__存放文件路徑

入口文件和普通模塊內(nèi)置變量的區(qū)別

print('package: ' + (__package__ or 當(dāng)前模塊不屬于任何包)) #當(dāng)前模塊不屬于任何包 print('name: ' + __name__) #__main__ print('doc: ' + (__package__ or 當(dāng)前模塊沒有文檔注釋)) print('file: ' + __file__) #文件名c9.py

__name__的經(jīng)典應(yīng)用

if __name == '__main__':pass #作為可執(zhí)行文件時才會執(zhí)行 #Make a script both importable and executabl
  • python -m seven.c15把c15按模塊執(zhí)行,命名空間(?)
    python seven\c15.py路徑方式

相對導(dǎo)入和絕對導(dǎo)入

  • 決定頂級包的是可執(zhí)行文件
    package2.package4,demo不是頂級包
  • 絕對導(dǎo)入必須從頂級包開始
  • 相對路徑:
    .表示當(dāng)前目錄
    …表示上層目錄
    …表示上上層目錄
  • 入口文件不能使用相對路徑
    因為入口文件的__name__被設(shè)置成__main__無法作為路徑使用
    一定要在路口文件使用相對路徑:
    回到demo的上一級,python -m demo.main,此時相對導(dǎo)入可用,輸出demo.package2.package4
  • 相對導(dǎo)入
from .m3 import m from ...m5 import m # attempted relative import beyond top-level package

Python 函數(shù)

返回

函數(shù)

  • round(a, 2)保留小數(shù)點后兩位,同時四舍五入
  • help(round)查看內(nèi)置函數(shù)
  • import this打印python之禪
  • 特點:功能性、隱藏細(xì)節(jié)、避免編寫重復(fù)的代碼

函數(shù)的定義和運行特點

def funcname(parameter_list):pass #1. 參數(shù)列表可以沒有 #2. return value None
  • [Previous line repeated 995 more times]遞歸超過995次
import sys sys.setrecursionlimit(100) #設(shè)置最大遞歸層數(shù) #[Previous line repeated 95 more times]

返回多個結(jié)果

def damage(skill1, skill2):damage1 = skill1 * 3damage2 = skill2 * 2return damage1, damage2skill1_damage, skill2_damage = damage(3, 4) #用兩個變量(有意義的變量名)存放兩個返回值 #序列解包

序列解包

d = 1, 2, 3 print(type(d)) #tuplea, b, c = d #序列解包 a, b = [1, 2, 3] #報錯,用兩個變量接收三個值a=b=c=1 #連續(xù)賦值√

參數(shù)

必須參數(shù)與關(guān)鍵字參數(shù)

  • 必須參數(shù):
    c = add(3, 2)
  • 關(guān)鍵字參數(shù):
    c = add(y=3, x=2),不用固定實參的輸入順序
  • 備注:
    二者的差別在函數(shù)的調(diào)用上,不在定義上
    ② 定義了多少形參就要傳入多少實參

默認(rèn)參數(shù)

  • 定義的時候給形參默認(rèn)值
  • 調(diào)用時正常傳遞實參即可按順序覆蓋,沒有默認(rèn)值的形參必須傳入實參
  • 必須傳入的參數(shù)必須放在默認(rèn)參數(shù)前面
  • print_student('lxxx', age=17)可以不按參數(shù)列表順序傳入改變默認(rèn)值
  • 默認(rèn)值參數(shù)和必須參數(shù)不能混著調(diào)用
    print_student('lxxx', gender='nv', 17, college='xx')

可變參數(shù)/形參列表可變

def demo(*param):print(param) print(type(param)) #tupledemo(1,2,3,4,5,6)a = (1,2,3,4,5) demo(a) #報錯,傳遞進(jìn)入的是一個元組 demo(*a) #√ 類似解包,傳入的是可變參數(shù)def demo(param1, param2=2, *param):print(param1) print(param2)print(param)demo('a', 1,2,3) #a #1 默認(rèn)值參數(shù)在前,讀完才讀可變參數(shù) #(2,3)def demo(param1, *param, param2=2):print(param1) print(param2)print(param)demo('a', 1,2,3, 'param') #a #(1,2,3,'param') 可變參數(shù)會把剩余全部傳入可變 #2demo('a', 1,2,3, param2='param') #a #(1,2,3) #param

盡量保證形參列表的簡單

關(guān)鍵字可變參數(shù)/任意個數(shù)的關(guān)鍵字參數(shù)

def city_temp(**param)print(type(param)) #dictfor key,value in param.items():print(key, ':', value)print(param)a = {'bj':'32c', 'sh':'31c'} city_temp(**a) city_temp() #{}

作用域

變量作用域

c = 50 #全局變量 def demo():c = 10 #局部變量print(c) #10def demo1():print(c) #50demo() print(c) #50def demo2():for i in range(0,9):a += iptint(a) #python沒有塊級變量的概念

作用域鏈

c = 1 def func1():c = 2def func2():c = 3print(c)func1() #3 2 1

global關(guān)鍵字

def demo():global cc = 2demo() print(c)
  • 全局變量在整個程序里面都能用

小作業(yè)1-合成石頭劃算不

要求




代碼

  • stone.py
''' this is about class stone '''class Stone():level = 1value = 0l1_diamond = 8l1_value = 0.75up_num = 12up_gold = 0.39up_vit = 10up_rate = 1def l1_to_l3(self):self.value += 13*self.l1_valueself.value += 13*self.l1_diamond*0.05self.value += self.up_goldself.value += self.up_vit*1self.level = 3self.up_gold = 0.897self.up_vit = 10self.up_rate = 0.4878def l3_to_l4(self):temp_sum = 0temp_sum += 16*self.l1_valuetemp_sum += 16*self.l1_diamond*0.05temp_sum += self.up_goldtemp_sum += self.up_vit*1self.value += temp_sum*self.up_ratetemp_sum = 0temp_sum += 16*self.l1_valuetemp_sum += 16*self.l1_diamond*0.05temp_sum += self.up_goldself.value += temp_sum*(1-self.up_rate)self.level = 4self.up_gold = 19.75self.up_vit = 10self.up_rate = 1def l4_to_l6(self):self.value += 12*self.valueself.value += self.up_goldself.value += self.up_vit*1
  • main.py
from stone import Stones1 = Stone() s1.l1_to_l3() s1.l3_to_l4() s1.l4_to_l6() composite_value = s1.value buy_value = 750 print('composite value is ' + str(composite_value)) if composite_value<buy_value:print('It\'s more cost-effective to synthesize yourself.') else:print('Buying directly is more cost-effective.')

結(jié)果

面向?qū)ο?/h2>

返回

  • 有意義的面向?qū)ο蟮拇a

定義

  • 首字母大寫,不要用下劃線連接
  • 類只負(fù)責(zé)描述定義,不負(fù)責(zé)執(zhí)行=類內(nèi)不能運行調(diào)用這個類
    一個模塊專門用來定義類,調(diào)用寫進(jìn)另外的模塊
  • 類最基本的作用:封裝
class Student(): name = ''age = 0def print_file(self): #即使不需要調(diào)用任何參數(shù)還是要在定義的時候加入selfprint('name:' + self.name)print('age:' + str(self.age))#實例化 student = Student() student.print_file() #調(diào)用類下面的方法
  • 方法與函數(shù)的區(qū)別
    方法:設(shè)計層面
    函數(shù):程序運行的過程式

類和對象的關(guān)系

  • 實例化
  • 類的設(shè)計:行為與特征
  • 類是模板,可以產(chǎn)生很多不同的對象

構(gòu)造函數(shù)

  • 實例化的過程中會自動調(diào)用構(gòu)造函數(shù),一般不顯示調(diào)用構(gòu)造函數(shù)
  • 構(gòu)造函數(shù)不能返回除了None以外的值(也不是用來返回什么東西的)
  • 構(gòu)造函數(shù)的作用,讓模板生成不同的對象

類變量、實例變量、self

class Student():name = 'qiyue' #類變量age = 0def __init__(self, name, age): #添加參數(shù)以后必須要傳入?yún)?shù)self.name = name self.age = ageprint('student') #實例變量student1 = Student('石敢當(dāng)', 18) student2 = Student() #報錯 print(student1.name) #石敢當(dāng) print(Sturent.name) #qiyue
  • 為什么要寫self,顯勝于隱

實例方法、類方法、靜態(tài)方法

  • 實例方法:def do_homework(self):
    實例可以調(diào)用的方法,操作實例變量
  • 在實例方法里面訪問類變量
print(Student.sum1) print(self.__class__.sum1)

不能直接用變量名訪問類變量

''' 實例方法調(diào)用類變量 ''' class Student():name = ''age = 0sum_s = 0def __init__(self, name, age)self.name = nameself.age = age#self.__class__.sum_s += 1#print('當(dāng)前學(xué)生總數(shù)為:' + str(self.__class__.sum_s))''' 定義類方法 '''@classmethoddef plus_sum(cls)cls.sum_s += 1print(cls.sum_s)''' 定義靜態(tài)方法 '''@staticmethoddef add(x,y):print('This is a static method')s1 = Student('石敢當(dāng)', 18) #當(dāng)前學(xué)生總數(shù)為:1 Student.plus_sum() s2 = Student('喜小樂', 16) #當(dāng)前學(xué)生總數(shù)為:2 Student.plus_sum() s1.plus_sum() #python中實例對象可以調(diào)用類方法,但是不建議這么干! s1.add(1,2) Student.add(1,2)
  • 靜態(tài)方法和面向?qū)ο箨P(guān)系很弱,像一個普通函數(shù),一般不推薦使用

成員可見性

  • 成員:變量和方法
  • 類有內(nèi)外之分
def do_homework(self):self.do_english_homework() #內(nèi)部調(diào)用print('homework')def do_english_homework(self):print('english homework')s1 = Student('石敢當(dāng)', 18) s1.do_homework() #外部調(diào)用
  • 提倡的規(guī)范:
    所有類下變量的更改都通過方法操作(對數(shù)據(jù)保護(hù),避免不規(guī)范操作)

公開和私有

  • 公開的 public:可以在外部直接調(diào)用
    私有的 private:外部無法直接讀取/設(shè)置
  • python怎么判斷公開還是私有?
    方法在開頭加雙下劃線__,變?yōu)樗接?br /> 為什么__init__可以在外部調(diào)用?因為它后面也有下劃線!這是python內(nèi)置函數(shù)的命名風(fēng)格

沒有什么是不可以訪問的!

s1 = Student('石敢當(dāng)', 18) s2 = Student('喜小樂', 16) s1.__score = -1 #給實例對象創(chuàng)建了一個新的屬性并賦值,不是給私有成員賦值 print(s1.__score) #-1 print(s2.__score) #報錯 print(s1.__dict__) #打印變量 #{'name':'石敢當(dāng)', 'age':18, '_Student__score':59, '__score':-1} print(s1._Student__score) #成功讀取!但是沒什么意義不建議這么玩

面向?qū)ο笕筇匦?/h3>
  • 繼承性、封裝性(抽象程度高)、多態(tài)性

繼承性

  • 避免定義重復(fù)的方法、重復(fù)的變量
from c6 import Human ''' class Human():sum = 0def __init__(self, name, age):self.name = nameself.age = agedef get_name(self):print(self.name) ''' class Student(Human):passprint(Student.sum) #0,從Human里面繼承的 s1 = Student('石敢當(dāng)', 18) print(s1.name) #以下都可以繼承 print(s1.age) s1.getname()

  • 單繼承。Python允許多繼承,單繼承都沒用好請別用多繼承
def __init__(self, school, name, age):self.school = schoolHuman.__init__(self, name, age) #顯式調(diào)用#為什么不傳入self會報錯?#類調(diào)用了實例方法,就是一個普通方法的調(diào)用,參數(shù)要傳全#s1 = Student() python內(nèi)部實例化機制自動幫我們調(diào)用,會補全self#對比s1.do_homewor()也不需要self,實例調(diào)用實例方法#強行需要用類調(diào)用:Student.do_homework(s1)#不建議這么干沒得意義,Student.do_homework('')都可以,只要傳一個參數(shù)進(jìn)入就行super(Student, self).__init__(name, age)#更改父類時只需要在定義類后面的括號里修改父類名稱即可
  • 子類與父類方法同名
'''def do_homework(self):print('This is a parent method') '''def do_homework(self):super(Student, self).do_homework() #1print('english homework')s1 = Student('人民路小學(xué)', '石敢當(dāng)', 18) s1.do_homework() #english homework #1 This is a parent method #1 english homework

正則表達(dá)式與JSON

返回

  • 正則表達(dá)式是一個特殊的字符序列,檢測一個字符串是否與我們所設(shè)定的字符序列相匹配,實現(xiàn)快速檢索文本、替換文本的操作。
    ① 檢查一串?dāng)?shù)字是否是電話號碼
    ② 檢測一個字符串是否符合E-mail
    ③ 把文本里指定的單詞替換為另一個單詞
import re #幾乎沒有意義的常量表達(dá)式,沒有體現(xiàn)出匹配的優(yōu)勢 #正則表達(dá)式的靈魂在于:規(guī)則! a = 'C|C++|Java|C#|Python|Javascript' r = re.findall('Python', a) #'正則表達(dá)式' if len(r) > 0:print('字符串中包含Python')

元字符

元字符與普通字符

import re #找a中的所有數(shù)字 a = 'C0C++7Java8C#9Python6Javascript' r = re.findall('\d', a) #\d匹配一個數(shù)字符,元字符 #\D匹配所有非數(shù)字符 print(r) #['0','7','8','9','6']

正則表達(dá)式匹配的是字符
菜鳥教程–元字符列表

字符集

import re #找s中找出中間字符是c或者f的單詞 s = 'abc,acc,adc,aec,afc,ahc' r = re.findall('a[cf]c', s) #普通字符+字符集 print(r) #[acc','afc'] r = re.findall('a[^cfd]c', s) #取反操作 print(r) #['abc','aec','ahc'] r = re.findall('a[c-f]c', s) #取范圍 print(r) #['acc','adc','aec','afc']
  • 普通字符用于輔助定界
  • 出現(xiàn)在字符集里面的字符之間是或關(guān)系

概括字符集

  • \d = [0-9],\D = [^0-9]
  • \w = [A-Za-z0-9_]匹配數(shù)字、字母、下劃線,\W
    ['p','y','t','h','o','n'],[' ','&','\n','\r','\t']
  • \s
    [' ','\n','\r','\t']–空白字符
  • .匹配除了換行符以外的所有符號

數(shù)量詞

a = 'python 1111java678ph' r = re.findall('[a-z]', a) print(r) #單個字母的序列 r = re.findall('[a-z][a-z][a-z]', a) #連續(xù)匹配3位字符 print(r) #['pyt','hon','jav','php'] r = re.findall('[a-z]{3}', a) print(r) #['pyt','hon','jav','php'] r = re.findall('[a-z]{3,6}', a) #字符位數(shù)范圍3-6 print(r) #['python','java','php']

貪婪和非貪婪

  • python默認(rèn)貪婪的匹配方式,一直匹配到某個字符不滿足他的要求
r = re.findall('[a-z]{3,6}?', a) #非貪婪 print(r) #['pyt','hon','jav','php']

匹配0次1次或者無限次

  • *匹配*前面的字符0次或者無限多次
  • +匹配*前面的字符1次或者無限多次
  • ?匹配*前面的字符0次或者1次
a = 'pytho0python1pythonn2' r = re.findall('python*', a) print(r) #['pytho','python','pythonn'] #n符合*匹配0次 r = re.findall('python+', a) print(r) #['python','pythonn'] #n符合*匹配0次 r = re.findall('python?', a) print(r) #['pytho','python','python'] #多出來的次數(shù)n會被去掉
  • ?可以用來去重

邊界匹配

  • ^從字符串的開頭開始匹配
  • $從字符串的末尾開始匹配
qq = '100000001' r = re.findall('\d{4,8}', qq) print(r) #['10000000'],在表達(dá)式里面尋找,并不完整的匹配字符串 r = re.findall('^\d{4,8}$', qq) print(r) #[],完整匹配了字符串 r = re.findall('000', qq) print(r) #['000','000'] r = re.findall('^000', qq) print(r) #[] r = re.findall('000$', qq) #最后三個字符得是000 print(r) #[]

import re s = 'pythonpythonpythonpythonpythonpython' r = re.findall('pythonpythonpython', s) print(r) #['pythonpythonpython', 'pythonpythonpython'] r = re.findall('python{3}', s) print(r) #[],只能匹配單個字符出現(xiàn)的次數(shù) r = re.findall('(python){3}', s) print(r) #['python', 'python'] ???? r = re.findall('(python){3}[JS]', s) print(r) #[]

匹配模式參數(shù)

  • re.I表示匹配忽視字母大小寫
  • re.S表示.匹配所有符號,包括\n
import re lanuage = 'PythonC#\nJavaPHP' r = re.findall('c#', lanuage, re.I) #匹配忽視大小寫 print(r) #['C#'] r = re.findall('c#.{1}', lanuage, re.I) #匹配c#和任意一個字符 print(r) #[],.不支持\n r = re.findall('c#.{1}', lanuage, re.I | re.S) print(r) #['C#\n']

re模塊下的其他函數(shù)

re.sub正則替換

import re lanuage = 'PythonC#Java' lanuage1 = 'PythonC#JavaC#PHPC#' r = re.findall('C#', 'GO', lanuage) print(r) #PythonGOJava r = re.findall('C#', 'GO', lanuage1, 0) #所有符號的都會被替換 print(r) #PythonGOJavaGOPHPGO r = re.findall('C#', 'GO', lanuage1, 1) #符合條件的字符替換的最大次數(shù)1 print(r) #PythonGOJavaC#PHPC#lanuage1 = lanuage1.replace('C#', 'GO') #內(nèi)置函數(shù)實現(xiàn)替換 print(lanuage1) #PythonGOJavaGOPHPGO
  • sub()的第二個參數(shù)可以是函數(shù)
lanuage1 = 'PythonC#JavaC#PHPC#' def conver(value): #傳入值是C#/非字符串,返回值會替代C#passdef conver1(value):print(value)#<_sre.SRE_Match object; span=(6, 8), match='C#'>,之前偶6個字符,占用的是7和8#<_sre.SRE_Match object; span=(12, 14), match='C#'>#<_sre.SRE_Match object; span=(17, 19), match='C#'>#如何拿到c#?matched = value.group() #表示匹配的字符串return '!!' + matched + '!!'r = r.sub('C#', convert, lanuage1) print(r) #PythonJavaPHP,因為返回值是空 r = r.sub('C#', convert1, lanuage1) #c#被動態(tài)的替換 print(r) #Python!!C#!!Java!!C#!!PHP!!C#!!
  • 把函數(shù)作為參數(shù)傳入的作用
s = 'A8C3721D86'def convert(value):matched = value.group()if (int)matched >= 6:return '9'else:return '0'r = re.sub('\d', convert, s) print(r) #A9C0900D99

search和match

  • match()從首字母開始匹配,首字母沒有就返回空
  • search()搜索字符串,一旦找到第一個就會返回
  • 兩者匹配成功立刻停止搜索,findall()會匹配所有符合的結(jié)果
import re s = 'A83C72D1D8E67' r = re.match('\d', s) print(r) #None r = re.search('\d', s) print(r) #<_sre.SRE_Match object; span=(0, 1), match='8'> s = '83C72D1D8E67' r = re.match('\d', s) print(r) #<_sre.SRE_Match object; span=(0, 1), match='8'> print(r.span()) print(r.group()) #8

group分組

#匹配life和python中間的內(nèi)容 s = 'life is short,i use python' r = re.search('(life.*python)', s) print(r.group(0)) #life is short,i use python只有一個組 r = re.search('life(.*)python', s) print(r.group(0)) #life is short,i use python,第一組存放整體 print(r.group(1)) # is short,i use r = re.findall('life(.*)python', s) print(r) #[' is short,i use ']s = 'life is short, i use python, i love python' r = re.findall('life(.*)python(.*)python', s) print(r.group(0)) #life is short, i use python, i love python print(r.group(1)) # is short,i use print(r.group(2)) #, i love print(r.group(0,1,2)) #('life is short, i use python, i love python', ' is short,i use ', ', i love ') 用元組返回 print(r.groups()) #(' is short, i use ', ', i love ') 不會返回完整的,只會返回匹配的部分

正則表達(dá)式的學(xué)習(xí)建議

  • 完成內(nèi)置函數(shù)無法完成的字符串相關(guān)問題
  • 常用的qq號,電話號碼,email的匹配,可以直接用別人寫好的提高效率,分析一下別人怎么寫的(學(xué)習(xí)角度)
  • 避免過度依賴內(nèi)置函數(shù),有意識的多用正則表達(dá)式

JSON

  • JavaScript Object Notation–JavaScript對象標(biāo)記
  • 是一種輕量級的數(shù)據(jù)交換格式
  • 字符串是JSON的表示形式
  • 符合JSON格式的字符串叫JSON字符串{"name":"qiyue"}
  • 優(yōu)勢:易于閱讀、解析,網(wǎng)絡(luò)傳輸效率高,適合用于跨語言交換數(shù)據(jù)

反序列化

  • 由字符串到某種語言上的數(shù)據(jù)結(jié)構(gòu)–反序列化
json_str = '{"name":"qiyue", "age":18}' #json格式字符串必須用雙引號,因此python里外層就要用單引號 student = json.loads(json_str) #把json字符串格式轉(zhuǎn)化成python能接受的數(shù)據(jù)結(jié)構(gòu) print(type(student)) #dict print(student) #{'name':'qiyue', 'age':18}字典 print(student['name']) #qiyue print(student['age']) #18#JSON object array json_str = '[{"name":"qiyue", "age":18}, {"name":"qiyue", "age":18}]' student = json.loads(json_str) print(type(student)) #list print(student) #[{'name':'qiyue', 'age':18}, {'name':'qiyue', 'age':18}]json_str = '[{"name":"qiyue", "age":18, "flag":false}, {"name":"qiyue", "age":18}]' student = json.loads(json_str) print(student) #[{'name':'qiyue', 'age':18, 'flag':False}, {'name':'qiyue', 'age':18}]

序列化

  • python數(shù)據(jù)類型向JSON字符串轉(zhuǎn)換的過程
jsonpython
objectdict
arraylist
stringstr
numberint
numberfloat
trueTrue
falseFalse
nullNone
import json student = [{'name':'qiyue', 'age':18, 'flag':False},{'name':'qiyue', 'age':18}] json_str = json.dumps(student) print(type(json_str)) #str print(json_str) #[{"name":"qiyue", "age":18, "flag":false}, {"name":"qiyue", "age":18}]
  • 調(diào)用服務(wù)拿到字符串(JSON)進(jìn)python處理

JSON/JSON對象/JSON字符串

  • JSON:是一種輕量級的數(shù)據(jù)交換格式
  • JSON字符串:符合JSON格式的字符串叫JSON字符串
  • JSON對象:JavaScript里的說法
  • JSON數(shù)據(jù)類型:中間數(shù)據(jù)類型/語言格式
  • JSON是REST服務(wù)的標(biāo)準(zhǔn)格式

Python高級語法與用法

返回

枚舉

枚舉是個類啊!

form enum import Enumclass VIP(Enum):#常量大寫,Python沒有常量概念#枚舉下的類型不易更改、不能重復(fù)--枚舉類型的保護(hù)功能YELLOW = 1GREEN = 2BLACK = 3RED = 4print(VIP.YELLOW) #VIP.YELLOW,并不是1
  • 枚舉的意義所在,關(guān)注的是名字而不是數(shù)字,重在標(biāo)簽

相比普通類有什么優(yōu)勢

yellow = 1 green = 2{'yellow':1, 'green':2}class TypeDiamond():yellow = 1green = 2
  • 缺陷:可變;沒有防止相同值的功能

相關(guān)操作

  • 取值
#訪問對應(yīng)取值 print(VIP.GREEN.value) #2 #訪問標(biāo)簽名 print(VIP.GREEN.name) #GREEN print(VIP.GREEN) #VIP.GREEN print(type(VIP.GREEN.name)) #<class 'str'> print(type(VIP.GREEN)) #<enum 'VIP'> print(VIP['GREEN']) #VIP.GREEN,通過枚舉名稱獲得枚舉類型
  • 遍歷
for v in VIP:print(v) #VIP.YELLOW #VIP.GREEN #VIP.BLACK #VIP.RED
  • 比較
class VIP1(Enum):YELLOW = 1GREEN = 2BLACK = 3RED = 4result = VIP.GREEN==2 print(result) #False result = VIP.GREEN==VIP.GREEN print(result) #Trueresult = VIP.GREEN>VIP.BLACK print(result) #報錯,枚舉類型之間不支持大小比較,可以等值比較result = VIP.GREEN is VIP.GREEN print(result) #身份的比較,Trueresult = VIP.GREEN==VIP1.GREEN print(result) #False,兩個不同的類,即使數(shù)值相同也不是一個枚舉

枚舉轉(zhuǎn)換

  • 在數(shù)據(jù)庫里存儲–用數(shù)字代表類型
  • 編寫代碼時顯示定義一個枚舉類,用枚舉類下的每一個枚舉類型對應(yīng)數(shù)據(jù)庫中的每個數(shù)值
  • 如何把數(shù)字和枚舉類型對應(yīng)起來?
a = 1 print(VIP(a)) #VIP.YELLOW #使用數(shù)值訪問具體的枚舉類型的一種方案

注意事項

  • 標(biāo)簽名不能相同,數(shù)值可以相同,但是!!
    允許有兩個類型數(shù)值相等,此時第二種可以看成是第一種的別名
  • 遍歷時不會打印別名
class VIP(Enum):YELLOW = 1GREEN = 1#YELLOW_ALIAS = 1BLACK = 3RED = 4print(VIP.GREEN) #VIP.YELLOWfor v in VIP:print(v) #VIP.YELLOW #VIP.BLACK #VIP.REDfor v in VIP.__members__.items(): #內(nèi)置變量屬性__members__的items方法print(v) #('YELLOW', <VIP.YELLOW: 1>) #('GREEN', <VIP.YELLOW: 1>) #('BLACK', <VIP.BLACK: 3>) #('RED', <VIP.RED: 4>)for v in VIP.__members__:print(v) #VIP.YELLOW #VIP.GREEN #VIP.BLACK #VIP.RED
  • IntEnum
from enum import Enum from enum import IntEnum, unique@unique #裝飾器 class VIP(IntEnum):YELLOW = 1YELLOW_A = 1GREEN = 'str'BLACK = 3RED = 4 #報錯,IntEnum的賦值必須是整型,Enum不會對枚舉的數(shù)值有限制 #報錯,使用裝飾器后不允許相同取值
  • 枚舉類型在python里面是單例模式,實例化沒有意義

進(jìn)階–函數(shù)式編程

  • 基礎(chǔ)知識用來寫出代碼,高階知識用來寫出可復(fù)用的代碼(包、類庫)
    嘗試著寫包和類庫,體會高級語法的好處,實踐出真知啊!

閉包

  • Python一切皆對象
  • 函數(shù)既可以作傳入?yún)?shù),又可以作返回結(jié)果
  • 閉包:函數(shù)及其在定義時外部的環(huán)境變量(非全局),不會受重新復(fù)賦值的影響
def curve_pre():a = 25 def curve(x): return a*x*xreturn curvea = 10 f = curve_pre() print(f(2)) #100 print(f.__closure__) #(<cell at 0x005E4250: int object at 0x5038D5B0>,) print(f.__closure__[0].cell_contents) #25
  • 經(jīng)典誤區(qū)
def f1():a = 10def f2():a = 20 #局部變量不影響外部環(huán)境變量print(a)print(a)f2()print(a)f1() #不是閉包
  • 小作業(yè):計算旅行者的路徑長度
#非閉包法 origin = 0def go(step):#global origin 使得該函數(shù)里面引用的origin位全局變量,不會報錯new_pos = origin + step #報錯,此時局部變量origin沒有值origin = new_pos #定義時在左邊出現(xiàn)的位局部變量return new_posprint(go(2)) #2 print(go(3)) #5 print(go(6)) #11 print(origin) #11,全局變量的值改變了#閉包方法 def factory(pos):def go(step):nonlocal pos #指定pos為非局部變量,優(yōu)先取環(huán)境變量new_pos = pos + steppos = new_posreturn new_posreturn gof = factory(origin) print(f(3)) #3 print(f(5)) #8 print(f(7)) #15 print(origin) #0,閉包方法調(diào)用函數(shù)不會改變?nèi)肿兞?/span>
  • 閉包特點:在模塊層面簡介調(diào)用函數(shù)內(nèi)部的局部變量

函數(shù)式編程

返回

匿名函數(shù)

lambda表達(dá)式

  • 定義時不需要定義它的函數(shù)名
lambda parameter_list: expression #表達(dá)式def add(x, y)return x+yprint(add(1,2)) #3 f = lambda x,y: x+y print(f(1,2)) #3 f = lambda x,y: a = x+y #報錯,冒號后面不能是代碼塊

三元表達(dá)式

  • xy,x大于y則返回x,否則y
#x>y ? x : y #條件為真時返回的結(jié)果 if 條件判斷 else 條件為假時的返回結(jié)果 r = x if x>y else y

map(class)

list_x = [0,1,2,3,4,5,6,7,8,9]def square(x):return x*xfor x in list_x:square(x)r = map(square, list_x) print(r) #<map object at 0x023D4A30> print(type(r)) #<class 'map'> print(list(r)) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],轉(zhuǎn)化成列表
  • map(函數(shù), 元素集合):將元素按函數(shù)方法映射成新的元素集合

map 與 lambda

  • 列表傳入個數(shù)與lambda的參數(shù)列表個數(shù)相同
  • 結(jié)果列表元素個數(shù)取決于傳入列表中元素少的那個
r = map(lambda x: x*x, list_x) print(list(r)) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],可閱讀性比for循環(huán)更好list_x = [0,1,2,3,4,5,6,7,8,9] list_y = [0,1,2,3,4,5,6,7,8,9] r = map(lambda x, y: x*x + y, list_x, list_y) #可傳入可變參數(shù) print(list(r)) #[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]list_y = [0,1,2,3,4,5,6] r = map(lambda x, y: x*x + y, list_x, list_y) print(list(r)) #[0, 2, 6, 12, 20, 30, 42]

高階函數(shù)

reduce

from functools import reduce#連續(xù)計算,連續(xù)調(diào)用lambda list_x = [0,1,2,3,4,5,6,7,8,9] r = reduce(lambda x,y: x+y, list_x) #取前兩個元素,每次lambda運算的結(jié)果作為x送入后面的運算 print(r) #45list_x = ['0','1','2','3','4','5','6','7','8','9'] r = reduce(lambda x,y: x+y, list_x, 'aaa') #初始值作為第一次運算的傳入?yún)?shù) print(r) #aaa0123456789

filter–過濾

  • 幫助我們過濾掉不符合定義格式的元素
  • 函數(shù)返回至為False
list_x = [1,0,1,0,0,1] r = filter(lambda x: True if x==1 else False, list_x) print(r) #<filter object at 0x006E4A10> print(list(r)) #[1, 1, 1]

函數(shù)式編程vs命令式編程

  • 命令式編程:def、if else、for
  • 函數(shù)式編程:map、reduce、filter、lambda
  • lisp居然是函數(shù)式編程的鼻祖!

裝飾器

  • 類此C#的特性,JAVA的注解

對修改是封閉的,對擴(kuò)展是開放的

  • 非裝飾器方法
import timedef f1():print('This is a function')def f2(): #沒有和新增的定義關(guān)聯(lián)起來,依舊是一個獨立函數(shù)print('This is a function')def print_current_time(func): #傳入函數(shù),保證函數(shù)時封閉的同時在每次調(diào)用函數(shù)前輸出時間戳--新增功能print(time.time())func()print_current_time(f1) print_current_time(f2)#和直接打印沒有區(qū)別 print(time.time()) f1() print(time.time()) f2()
  • 裝飾器方法–裝飾器是一種模式
import timedef decorator(func): #裝飾def wrapper(): #封裝print(time.time())func()return wrapperdef f1():print('This is a function1')def f2():print('This is a function2')f = decorator(f1) f()

python語法糖–甜、甜的?

  • 語法糖: 真正體現(xiàn)裝飾器功能的高光時刻!即沒有改變函數(shù)內(nèi)部實現(xiàn),也沒有改變函數(shù)的調(diào)用
  • 可以接受定義時候的復(fù)雜,但是絕對不能接受調(diào)用時候的復(fù)雜!
import timedef decorator(func): #裝飾def wrapper(): #封裝print(time.time())func()return wrapper@decorator #真正體現(xiàn)裝飾器功能的高光時刻!即沒有改變函數(shù)內(nèi)部實現(xiàn),也沒有改變函數(shù)的調(diào)用 def f1():print('This is a function1')def f2():print('This is a function2')f1() #保持原有的調(diào)用方式不變
  • 如果函數(shù)帶各種各樣的參數(shù)呢?
import timedef decorator(func): #裝飾def wrapper(*args): #封裝print(time.time())func(*args) #通用意義的變量名?return wrapper@decorator def f1(func_name):print('This is a function named ' + func_name)@decorator def f2(func_name1, func_name2):print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)f1('lizzy') f2('lxxx1', 'lxxx2')

如何兼容通用關(guān)鍵字參數(shù)?

import timedef decorator(func): #裝飾def wrapper(*args, **kw): #封裝print(time.time())func(*args, **kw) #不管函數(shù)是怎么定義的,都可以用這個抽象的函數(shù)調(diào)用方式return wrapper@decorator def f1(func_name):print('This is a function named ' + func_name)@decorator def f2(func_name1, func_name2):print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)@decorator def f3(func_name1, func_name2, **kw): #關(guān)鍵字參數(shù)print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)print(kw)f1('lizzy') f2('lxxx1', 'lxxx2') f3('test1', 'test2', a=1, b=2, c='123')''' 1587521895.7875009 This is a function named lizzy 1587521895.7885008 This is a function named lxxx1 This is a function named lxxx2 1587521895.7915008 This is a function named test1 This is a function named test2 {'a': 1, 'b': 2, 'c': '123'} '''
  • func(*args, **kw) 不管函數(shù)是怎么定義的,都可以用這個抽象的函數(shù)調(diào)用方式

裝飾器小結(jié)

  • 裝飾器優(yōu)勢
    代碼的穩(wěn)定性角度:對被封裝的單元做出修改–通過裝飾器改變函數(shù)的行為
    代碼的復(fù)用性角度:語法糖

實戰(zhàn):原生爬蟲

返回

  • 爬蟲的目的性要明確

整理爬蟲的常規(guī)思路

  • 鼠標(biāo)右鍵–檢查:開html信息
  • 點擊信息框左上角的小箭頭

    點擊頁面中需要的信息–自動定位到html信息中所屬的代碼段
  • 數(shù)據(jù)提取層級分析:精準(zhǔn)選取定位標(biāo)簽,選閉合的父級別標(biāo)簽,盡量不要選兄弟標(biāo)簽
  • 正則分析
  • 數(shù)據(jù)精煉
  • 數(shù)據(jù)處理(分析完成你的需求)

錯誤

  • UnicodeDecodeError ‘utf-8’ codec can’t decode byte 0x8b in position 1: invalid start byte報錯分析
  • StringIO和BytesIO–廖雪峰
  • gizp模塊介紹–python文檔

    ① 報錯代碼
from urllib import requestclass Spilder():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spilder.url)htmls = r.read()htmls = str(htmls, encoding='utf-8') #報錯,將htmls按utf-8編碼def go(self):self.__fetch_content()s = Spilder() s.go()

② 調(diào)試代碼

from urllib import request from io import BytesIO #BytesIO實現(xiàn)在內(nèi)存中讀寫bytes import gzip #壓縮與解壓縮的模塊class Spider():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()#print(type(htmls)) <class 'bytes'>buff = BytesIO(htmls) #寫入的不是str,而是經(jīng)過UTF-8編碼的bytes,即用一個bytes初始化BytesIO#print(type(buff)) <class '_io.BytesIO'>f = gzip.GzipFile(fileobj=buff) #將BytesIO對象解壓縮成GzipFile對象fprint(type(f)) #<class 'gzip.GzipFile'>htmls = f.read().decode('utf-8') #讀取f中的字節(jié)數(shù)據(jù)并按utf-8解碼為strprint(type(htmls)) #<class 'str'>a = 1def go(self):self.__fetch_content()s = Spider() s.go()

③ 修改代碼

from urllib import request from io import BytesIO import gzipclass Spider():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()buff = BytesIO(htmls)f = gzip.GzipFile(fileobj=buff)htmls = f.read().decode('utf-8')a = 1def go(self):self.__fetch_content()s = Spider() s.go()
  • 我跳票了我去爬B站學(xué)習(xí)直播區(qū)了再見斗魚!
from urllib import request from io import BytesIO import gzipclass Spider():url = 'https://live.bilibili.com/p/eden/area-tags?parentAreaId=1&areaId=27&visit_id=4tmkk5fiu6m'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()htmls = str(htmls, encoding = 'utf-8')return htmlsdef __analysis(self, htmls):passdef go(self):htmls = self.__fetch_content()self.__analysis(htmls)s = Spider() s.go()
  • anomalous backslash in string: ‘\s’. string constant might be missing an r prefix.
    問題:\s首先被認(rèn)為是轉(zhuǎn)義字符,在正則中多加一個\
    解決:([\\s\\S]*?)加一個反斜杠
  • root_info提取不到信息:頁面顯示的數(shù)據(jù)格式和抓取的數(shù)據(jù)格式有出入,根據(jù)抓取到的數(shù)據(jù)修改正則表達(dá)式

代碼規(guī)范

  • 模塊、類、方法:塊注釋,內(nèi)部首部多行
  • 語句注釋:在上面,注釋上空行
  • 不要濫用空行,不要在一個函數(shù)里面寫多行代碼(函數(shù)越小越靈活復(fù)用性越高,10-20行,最多30行)
  • 寫出來也要寫好
  • 爬蟲擴(kuò)展:BeautifulSoup、Scrapy等框架;爬蟲、反爬蟲、反反爬蟲;ip如果被封了–代理ip庫

實現(xiàn)代碼

  • main.py
from spider import Spiderspider1 = Spider() spider1.go()
  • spider.py
from urllib import request import reclass Spider():'''一個爬蟲類。屬性:url連接地址父集信息匹配格式root_pattern名字、人氣信息的匹配格式name_pattern、number_pattern方法:外部接口go()獲取頁面內(nèi)容__fetch_content(self)對頁面內(nèi)容分析提取所需信息__analysis(self, htmls)對數(shù)據(jù)提煉__refine(self, anchors)排序__sort(self, anchors)與排序規(guī)則__sort_seed(self, anchor)展示__show(self, anchors)'''__url = 'https://live.bilibili.com/p/eden/area-tags?parentAreaId=1&areaId=27&visit_id=4tmkk5fiu6m'__root_pattern = '<div class="room-anchor card-text p-relative" data-v-191d6a08>([\\s\\S]*?)</div>'__name_pattern = '<span title="([\\s\\S]*?)" data-v-191d6a08>'__number_pattern = '<span class="v-middle" data-v-191d6a08>([\\s\\S]*?)</span>'#頁面顯示的信息:<div data-v-191d6a08="" class="room-anchor card-text p-relative"><span data-v-191d6a08="" title="丸烏咪">丸烏咪</span><div data-v-191d6a08="" class="popular-ctnr p-absolute"><i data-v-191d6a08="" class="icon-font icon-popular v-middle dp-i-block"></i><span data-v-191d6a08="" class="v-middle">2460</span></div></div>#實際抓取的信息:<div class="room-anchor card-text p-relative" data-v-191d6a08><span title="padango" data-v-191d6a08>padango</span><div class="popular-ctnr p-absolute" data-v-191d6a08><i class="icon-font icon-popular v-middle dp-i-block" data-v-191d6a08></i><span class="v-middle" data-v-191d6a08>3199</span></div></div></div></div>def __fetch_content(self):'''獲取頁面的內(nèi)容'''r = request.urlopen(Spider.__url)htmls = r.read()htmls = str(htmls, encoding = 'utf-8')return htmlsdef __analysis(self, htmls):'''從提取的頁面內(nèi)容中匹配所需信息'''root_info = re.findall(Spider.__root_pattern, htmls)anchors = []for info in root_info:name = re.findall(Spider.__name_pattern, info)number = re.findall(Spider.__number_pattern, info)anchor = {'name':name, 'number':number}anchors.append(anchor)return anchorsdef __refine(self, anchors):'''數(shù)據(jù)精煉,轉(zhuǎn)化成易于處理的格式'''l = lambda anchor:{#strip()刪除多余的換行和空格'name':anchor['name'][0].strip(),'number':anchor['number'][0]}return map(l, anchors)def __sort(self, anchors):'''對數(shù)據(jù)排序'''#字典不支持比較,要取可以個支持比較的元素#sorted()默認(rèn)從小到大,reverse=True從大到小anchors = sorted(anchors, key=self.__sort_seed, reverse=True)return anchorsdef __sort_seed(self, anchor):'''排序規(guī)則'''r = re.findall('\\d*', anchor['number'])number = float(r[0])if '萬' in anchor['number']:number *= 10000return numberdef __show(self, anchors):'''數(shù)據(jù)展示'''for rank in range(0, len(anchors)):print('rank ' + str(rank+1)+ ':' + anchors[rank]['name']+ ' ' + anchors[rank]['number'])def go(self):'''作為接口供外部調(diào)用的方法'''htmls = self.__fetch_content()anchors = self.__analysis(htmls)anchors = list(self.__refine(anchors))anchors = self.__sort(anchors)self.__show(anchors)

存在的問題與改進(jìn)方向

  • 動態(tài)加載的頁面只能讀取30條信息–如何讀取動態(tài)頁面?
  • 如何使程序間隔xx時間重復(fù)爬取更新信息
  • 圖形界面數(shù)據(jù)展示
  • 獲得的數(shù)據(jù)還能做哪些方向的分析……?

Pythonic與Python雜記

返回

用字典代替switch

switcher = {0 : 'Sunday',1 : 'Monday',2 : 'Tuesday' }day = 2 day_name = switcher[day] print(day_name)day = 6 day_name = switcher[day] print(day_name) #報錯,6不存在 #get()方法有容錯性 day_name = switcher.get(day, 'Unknown') #找不到時返回Unknown print(day_name)
  • 字典內(nèi)部對應(yīng)為函數(shù)(實現(xiàn)一個分支多個語句)
def get_sunday():return 'Sunday'def get_monday():return 'Monday'def get_tuesday():return 'Tuesday'def get_default():return 'It\'s false.'switcher = {0 : get_sunday,1 : get_monday,2 : get_tuesday }day = 6; day_name = switcher.get(day, get_default)() print(day_name)

列表推導(dǎo)式

a = [1,2,3,4,5,6,7,8]#map實現(xiàn) b = map(lambda i: i*i, a) print(list(b))#列表推導(dǎo)式實現(xiàn) b = [i*i for i in a] print(b) #[1, 4, 9, 16, 25, 36, 49, 64] b = [i**3 for i in a] print(b) #[1, 8, 27, 64, 125, 216, 343, 512]
  • 推薦:有選擇性的篩選運算的場合
a = {1,2,3,4,5,6,7,8} b = [i**2 for i in a if i>=5] print(b) #[25, 36, 49, 64] b = {i**2 for i in a if i>=5} print(b) #{64, 25, 36, 49}
  • 列表、字典、元組、集合都可以用
  • 字典如何編寫列表推導(dǎo)式
students = {'喜小樂': 18,'石敢當(dāng)': 20,'橫小五': 15 }b = [key for key,value in students.items()] print(b) #['喜小樂', '石敢當(dāng)', '橫小五'] b = {value:key for key,value in students.items()} print(b) #{18: '喜小樂', 20: '石敢當(dāng)', 15: '橫小五'}#元組不可變,操作受限 b = (key for key,value in students.items()) print(b) #<generator object <genexpr> at 0x0059A5A0> for x in b:print(x) """ 喜小樂 石敢當(dāng) 橫小五 """

iterator與generator

  • 可迭代對象(凡是可以被for in遍歷的),迭代器
  • 可迭代對象不一定是迭代器(列表元組字典),迭代器一定是可迭代對象
  • 如何讓自定義的class可以被遍歷?–迭代器。
class Book:passclass BookCollection:def __init__(self):self.data = ['《往事》', '《只能》', '《回味》']self.cur = 0def __iter__(self):return self#for in調(diào)用nextdef __next__(self):if self.cur >= len(self.data):raise StopIteration()r = self.data[self.cur]self.cur += 1return rbooks = BookCollection() #迭代器一次性 for book in books:print(book) #迭代器異常 for book in books:print(book)print(next(books)) print(next(books)) print(next(books)) #迭代器異常 print(next(books))
  • 如何迭代兩次?
books = BookCollection() import copy #淺拷貝 books_copy = copy.copy(books) #迭代器一次性 for book in books:print(book) for book in books_copy:print(book)
  • 生成器–yield的用法
def gen(max):n = 0while n<=max:#print(n),我們想要的是0-10000的返回值,而不是直接在函數(shù)內(nèi)處理#接著上次執(zhí)行的結(jié)果繼續(xù)執(zhí)行下去yield nn += 1g = gen(10000) for i in g:print(i)

None

  • 無論是從【類型】還是【值】上面來講,【None】都不等于【空字符串、空列表,0,False】
print(type(None)) #<class 'NoneType'>
  • not a和a is None等同嗎?
def fun():return None a = fun() if not a:print('S') else:print('F') #S if a is None:print('S') else:print('F') #Sa = [] if not a:print('S') else:print('F') #S if a is None:print('S') else:print('F') #F
  • 推薦的判空操作:
    if a:
    if not a:
    不要用None來進(jìn)行判空操作

對象存在不一定是True

  • None永遠(yuǎn)對應(yīng)False
  • 自定義的對象和True和False是怎么對應(yīng)的?
class Test():passtest = Test() if test:print('S') #S,不存在len和bool時默認(rèn)trueclass Test1():def __len__(self):return 0test = Test1() if test:print('S') else:print('F') #F
  • __len__與__bool__內(nèi)置方法
class Test():def __len__(self):return 8#只能返回int,'8'會報錯,'1.0'也會報錯,bool可以print(len(Test())) #8 print(bool(Test())) #True,沒有bool方法就看len方法class Test1():def __bool__(self):return False #0報錯,強制要bool類型def __len__(self):return 8print(len(Test1())) #8 print(bool(Test1())) #False #加入__bool__以后bool取值不再看len

我!結(jié)!課!了!

總結(jié)

以上是生活随笔為你收集整理的Python语法--Mooc七月的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。