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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python语法--Mooc七月

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

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

vscode小技巧

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

目錄速查

Python入門導學
Python基本類型:數字,字符串
組:列表,元組,集合,字典
變量與運算符
分支、循環、條件和枚舉
包、模塊、類
函數
面向對象:類,實例,方法,繼承
正則表達式和JSON
枚舉類型,閉包
匿名函數、高階函數、裝飾器
爬蟲實戰
Python雜記

Python入門導學

返回

特點

  • 簡潔;豐富的標準庫和第三方庫(電子郵件、GUI);面向對象+函數式編程;易于上手,難于精通;既有動態腳本的特性,又有面向對象的特性。
  • 豆瓣、知乎
  • Simple is better than complex.
    Now is better than never. Although never is often better than an right now.
  • 缺點:慢
    編譯型語言(C、C++)–運行效率
    解釋型語言(Javascript,Python)–開發效率

一個經典誤區:編程 = web編程?

  • 世界上不是只有網站,還有很多問題需要編程來解決。
  • web是基礎–爬蟲、數據服務提供、數據分析。
  • 互聯網時代,有網絡的地方就需要web。
  • web編程確實是最好的語言實踐–業務邏輯思考能力、寬廣的知識面。

Python能做什么

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

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

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

返回

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

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

數字

整型與浮點型

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

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

10、2、8、16進制&表示&轉換

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

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

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

字符串str

單雙引號

  • 單引號和雙引號–成對出現
    "let's go",'let\'s go'

多行字符串

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

輸出'helloworld'

轉義字符–特殊的字符

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

原始字符串

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

字符串運算

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

“組”的概念與定義

返回

列表list

定義

列表內部可以存放不同類型元素
列表內部可以嵌套列表

基本操作

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

元組tuple

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

序列總結

  • 序號
  • 切片
    "hello world"[0:8:2]返回'hlow–在0-7的切片內隔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}不支持序號、切片
  • 不重復
    {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值不可重復
{'Q':"新月打擊",'W':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}['Q'] '新月打擊' {'Q':"新月打擊",'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}['Q'] '蒼白之瀑' {'Q':"新月打擊",'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"} {'Q':"蒼白之瀑",'E':"月之降臨",'R':"月神沖刺"}
  • value類型無限制,可以也是一個字典
    key必須是不可變的類型 – 字符串和元組不可變,列表可變

變量與運算符

返回

變量

什么是變量

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

命名規則

  • 字母、數字、下劃線
  • 首位不能是數字
  • 系統關鍵字(保留關鍵字)不能用在變量名中
    非保留的也盡量不要用,血和淚的教訓。
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()得到地址,發現前后地址變了,說明不是在原地址上修改 b = 'hello' b = b + 'python' #生成新的字符串,再賦值給b print(b) #hellopython
  • list和tuple:
    元組不可修改,能用元組就用元組 – 代碼穩定性考慮
a = (1,2,3,[1,2,['a','b','c']]) a[2] = '3' #不可改變,報錯 a[3][2][1] = '4' #可以改變,變為(1,2,3,[1,2,['a','4','c']])

運算符

算術運算符

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

賦值運算符

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

比較運算符

  • 返回一個bool值

邏輯運算符

  • 與、或、非
  • int,float中0被認為是False
    字符串中空字符串""是False
    列表中空的列表[]被認為是False
  • and 和 or 的返回值 – 最后一個讀到的內容
    1 and 2返回2,2 and 1返回1 – 讀到第二個數字才能判斷
    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',前面取負末位+1,-4 a = 2 bin(a) #'0b10' bin(a<<1) #'0b100' bin(a>>3) #'0b0'

分支、循環、條件和枚舉

返回

表達式

什么是表達式

表達式是運算符和操作數組成的序列

表達式優先級

  • 一般右結合,出現=左結合,與運算符優先級無關
  • 運算符優先級最高,然后是比較,邏輯運算符最低:not > and > or
  • 加輔助括號可以改變運算順序

流程控制語句

條件控制

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

pylint規范

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

循環

while的循環場景

  • 遞歸
counter = 1 while counter <= 10:counter += 1print(counter) else:print('EOF') #循環結束的時候執行else

for

for target_list in expression_list:pass else:pass #列表全部打完以后執行else,強制break結束時不會執行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的組織結構-包、模塊、類

返回

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

導入

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

init.py

  • 導入包時自動運行:
    無論是導入包還是導入包下面的模塊,都會自動運行__init__.py
  • 在__init__.py內設置__all__可以控制*時導入的包內模塊
  • 批量導入包
  • 注意點:
    ① 包和模塊不會被重復導入
    ② 避免循環導入
    ③ python導入模塊時會執行所導入模塊的代碼

模塊內置變量

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

入口文件和普通模塊內置變量的區別

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

__name__的經典應用

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

相對導入和絕對導入

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

Python 函數

返回

函數

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

函數的定義和運行特點

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

返回多個結果

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 #連續賦值√

參數

必須參數與關鍵字參數

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

默認參數

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

可變參數/形參列表可變

def demo(*param):print(param) print(type(param)) #tupledemo(1,2,3,4,5,6)a = (1,2,3,4,5) demo(a) #報錯,傳遞進入的是一個元組 demo(*a) #√ 類似解包,傳入的是可變參數def demo(param1, param2=2, *param):print(param1) print(param2)print(param)demo('a', 1,2,3) #a #1 默認值參數在前,讀完才讀可變參數 #(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') 可變參數會把剩余全部傳入可變 #2demo('a', 1,2,3, param2='param') #a #(1,2,3) #param

盡量保證形參列表的簡單

關鍵字可變參數/任意個數的關鍵字參數

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關鍵字

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

小作業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.')

結果

面向對象

返回

  • 有意義的面向對象的代碼

定義

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

類和對象的關系

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

構造函數

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

類變量、實例變量、self

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

實例方法、類方法、靜態方法

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

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

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

成員可見性

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

公開和私有

  • 公開的 public:可以在外部直接調用
    私有的 private:外部無法直接讀取/設置
  • python怎么判斷公開還是私有?
    方法在開頭加雙下劃線__,變為私有
    為什么__init__可以在外部調用?因為它后面也有下劃線!這是python內置函數的命名風格

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

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

面向對象三大特性

  • 繼承性、封裝性(抽象程度高)、多態性

繼承性

  • 避免定義重復的方法、重復的變量
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('石敢當', 18) print(s1.name) #以下都可以繼承 print(s1.age) s1.getname()

  • 單繼承。Python允許多繼承,單繼承都沒用好請別用多繼承
def __init__(self, school, name, age):self.school = schoolHuman.__init__(self, name, age) #顯式調用#為什么不傳入self會報錯?#類調用了實例方法,就是一個普通方法的調用,參數要傳全#s1 = Student() python內部實例化機制自動幫我們調用,會補全self#對比s1.do_homewor()也不需要self,實例調用實例方法#強行需要用類調用:Student.do_homework(s1)#不建議這么干沒得意義,Student.do_homework('')都可以,只要傳一個參數進入就行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('人民路小學', '石敢當', 18) s1.do_homework() #english homework #1 This is a parent method #1 english homework

正則表達式與JSON

返回

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

元字符

元字符與普通字符

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

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

字符集

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']
  • 普通字符用于輔助定界
  • 出現在字符集里面的字符之間是或關系

概括字符集

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

數量詞

a = 'python 1111java678ph' r = re.findall('[a-z]', a) print(r) #單個字母的序列 r = re.findall('[a-z][a-z][a-z]', a) #連續匹配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) #字符位數范圍3-6 print(r) #['python','java','php']

貪婪和非貪婪

  • python默認貪婪的匹配方式,一直匹配到某個字符不滿足他的要求
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'] #多出來的次數n會被去掉
  • ?可以用來去重

邊界匹配

  • ^從字符串的開頭開始匹配
  • $從字符串的末尾開始匹配
qq = '100000001' r = re.findall('\d{4,8}', qq) print(r) #['10000000'],在表達式里面尋找,并不完整的匹配字符串 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) #[],只能匹配單個字符出現的次數 r = re.findall('(python){3}', s) print(r) #['python', 'python'] ???? r = re.findall('(python){3}[JS]', s) print(r) #[]

匹配模式參數

  • 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模塊下的其他函數

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) #符合條件的字符替換的最大次數1 print(r) #PythonGOJavaC#PHPC#lanuage1 = lanuage1.replace('C#', 'GO') #內置函數實現替換 print(lanuage1) #PythonGOJavaGOPHPGO
  • sub()的第二個參數可以是函數
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#被動態的替換 print(r) #Python!!C#!!Java!!C#!!PHP!!C#!!
  • 把函數作為參數傳入的作用
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()會匹配所有符合的結果
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中間的內容 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 ') 不會返回完整的,只會返回匹配的部分

正則表達式的學習建議

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

JSON

  • JavaScript Object Notation–JavaScript對象標記
  • 是一種輕量級的數據交換格式
  • 字符串是JSON的表示形式
  • 符合JSON格式的字符串叫JSON字符串{"name":"qiyue"}
  • 優勢:易于閱讀、解析,網絡傳輸效率高,適合用于跨語言交換數據

反序列化

  • 由字符串到某種語言上的數據結構–反序列化
json_str = '{"name":"qiyue", "age":18}' #json格式字符串必須用雙引號,因此python里外層就要用單引號 student = json.loads(json_str) #把json字符串格式轉化成python能接受的數據結構 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數據類型向JSON字符串轉換的過程
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}]
  • 調用服務拿到字符串(JSON)進python處理

JSON/JSON對象/JSON字符串

  • JSON:是一種輕量級的數據交換格式
  • JSON字符串:符合JSON格式的字符串叫JSON字符串
  • JSON對象:JavaScript里的說法
  • JSON數據類型:中間數據類型/語言格式
  • JSON是REST服務的標準格式

Python高級語法與用法

返回

枚舉

枚舉是個類啊!

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

相比普通類有什么優勢

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

相關操作

  • 取值
#訪問對應取值 print(VIP.GREEN.value) #2 #訪問標簽名 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,兩個不同的類,即使數值相同也不是一個枚舉

枚舉轉換

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

注意事項

  • 標簽名不能相同,數值可以相同,但是!!
    允許有兩個類型數值相等,此時第二種可以看成是第一種的別名
  • 遍歷時不會打印別名
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(): #內置變量屬性__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不會對枚舉的數值有限制 #報錯,使用裝飾器后不允許相同取值
  • 枚舉類型在python里面是單例模式,實例化沒有意義

進階–函數式編程

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

閉包

  • Python一切皆對象
  • 函數既可以作傳入參數,又可以作返回結果
  • 閉包:函數及其在定義時外部的環境變量(非全局),不會受重新復賦值的影響
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
  • 經典誤區
def f1():a = 10def f2():a = 20 #局部變量不影響外部環境變量print(a)print(a)f2()print(a)f1() #不是閉包
  • 小作業:計算旅行者的路徑長度
#非閉包法 origin = 0def go(step):#global origin 使得該函數里面引用的origin位全局變量,不會報錯new_pos = origin + step #報錯,此時局部變量origin沒有值origin = new_pos #定義時在左邊出現的位局部變量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為非局部變量,優先取環境變量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,閉包方法調用函數不會改變全局變量
  • 閉包特點:在模塊層面簡介調用函數內部的局部變量

函數式編程

返回

匿名函數

lambda表達式

  • 定義時不需要定義它的函數名
lambda parameter_list: expression #表達式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 #報錯,冒號后面不能是代碼塊

三元表達式

  • xy,x大于y則返回x,否則y
#x>y ? x : y #條件為真時返回的結果 if 條件判斷 else 條件為假時的返回結果 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],轉化成列表
  • map(函數, 元素集合):將元素按函數方法映射成新的元素集合

map 與 lambda

  • 列表傳入個數與lambda的參數列表個數相同
  • 結果列表元素個數取決于傳入列表中元素少的那個
r = map(lambda x: x*x, list_x) print(list(r)) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],可閱讀性比for循環更好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) #可傳入可變參數 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]

高階函數

reduce

from functools import reduce#連續計算,連續調用lambda list_x = [0,1,2,3,4,5,6,7,8,9] r = reduce(lambda x,y: x+y, list_x) #取前兩個元素,每次lambda運算的結果作為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') #初始值作為第一次運算的傳入參數 print(r) #aaa0123456789

filter–過濾

  • 幫助我們過濾掉不符合定義格式的元素
  • 函數返回至為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]

函數式編程vs命令式編程

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

裝飾器

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

對修改是封閉的,對擴展是開放的

  • 非裝飾器方法
import timedef f1():print('This is a function')def f2(): #沒有和新增的定義關聯起來,依舊是一個獨立函數print('This is a function')def print_current_time(func): #傳入函數,保證函數時封閉的同時在每次調用函數前輸出時間戳--新增功能print(time.time())func()print_current_time(f1) print_current_time(f2)#和直接打印沒有區別 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語法糖–甜、甜的?

  • 語法糖: 真正體現裝飾器功能的高光時刻!即沒有改變函數內部實現,也沒有改變函數的調用
  • 可以接受定義時候的復雜,但是絕對不能接受調用時候的復雜!
import timedef decorator(func): #裝飾def wrapper(): #封裝print(time.time())func()return wrapper@decorator #真正體現裝飾器功能的高光時刻!即沒有改變函數內部實現,也沒有改變函數的調用 def f1():print('This is a function1')def f2():print('This is a function2')f1() #保持原有的調用方式不變
  • 如果函數帶各種各樣的參數呢?
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')

如何兼容通用關鍵字參數?

import timedef decorator(func): #裝飾def wrapper(*args, **kw): #封裝print(time.time())func(*args, **kw) #不管函數是怎么定義的,都可以用這個抽象的函數調用方式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): #關鍵字參數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) 不管函數是怎么定義的,都可以用這個抽象的函數調用方式

裝飾器小結

  • 裝飾器優勢
    代碼的穩定性角度:對被封裝的單元做出修改–通過裝飾器改變函數的行為
    代碼的復用性角度:語法糖

實戰:原生爬蟲

返回

  • 爬蟲的目的性要明確

整理爬蟲的常規思路

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

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

錯誤

  • 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()

② 調試代碼

from urllib import request from io import BytesIO #BytesIO實現在內存中讀寫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,而是經過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中的字節數據并按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站學習直播區了再見斗魚!
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首先被認為是轉義字符,在正則中多加一個\
    解決:([\\s\\S]*?)加一個反斜杠
  • root_info提取不到信息:頁面顯示的數據格式和抓取的數據格式有出入,根據抓取到的數據修改正則表達式

代碼規范

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

實現代碼

  • 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()獲取頁面內容__fetch_content(self)對頁面內容分析提取所需信息__analysis(self, htmls)對數據提煉__refine(self, anchors)排序__sort(self, anchors)與排序規則__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):'''獲取頁面的內容'''r = request.urlopen(Spider.__url)htmls = r.read()htmls = str(htmls, encoding = 'utf-8')return htmlsdef __analysis(self, htmls):'''從提取的頁面內容中匹配所需信息'''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):'''數據精煉,轉化成易于處理的格式'''l = lambda anchor:{#strip()刪除多余的換行和空格'name':anchor['name'][0].strip(),'number':anchor['number'][0]}return map(l, anchors)def __sort(self, anchors):'''對數據排序'''#字典不支持比較,要取可以個支持比較的元素#sorted()默認從小到大,reverse=True從大到小anchors = sorted(anchors, key=self.__sort_seed, reverse=True)return anchorsdef __sort_seed(self, anchor):'''排序規則'''r = re.findall('\\d*', anchor['number'])number = float(r[0])if '萬' in anchor['number']:number *= 10000return numberdef __show(self, anchors):'''數據展示'''for rank in range(0, len(anchors)):print('rank ' + str(rank+1)+ ':' + anchors[rank]['name']+ ' ' + anchors[rank]['number'])def go(self):'''作為接口供外部調用的方法'''htmls = self.__fetch_content()anchors = self.__analysis(htmls)anchors = list(self.__refine(anchors))anchors = self.__sort(anchors)self.__show(anchors)

存在的問題與改進方向

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

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)
  • 字典內部對應為函數(實現一個分支多個語句)
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)

列表推導式

a = [1,2,3,4,5,6,7,8]#map實現 b = map(lambda i: i*i, a) print(list(b))#列表推導式實現 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}
  • 列表、字典、元組、集合都可以用
  • 字典如何編寫列表推導式
students = {'喜小樂': 18,'石敢當': 20,'橫小五': 15 }b = [key for key,value in students.items()] print(b) #['喜小樂', '石敢當', '橫小五'] b = {value:key for key,value in students.items()} print(b) #{18: '喜小樂', 20: '石敢當', 15: '橫小五'}#元組不可變,操作受限 b = (key for key,value in students.items()) print(b) #<generator object <genexpr> at 0x0059A5A0> for x in b:print(x) """ 喜小樂 石敢當 橫小五 """

iterator與generator

  • 可迭代對象(凡是可以被for in遍歷的),迭代器
  • 可迭代對象不一定是迭代器(列表元組字典),迭代器一定是可迭代對象
  • 如何讓自定義的class可以被遍歷?–迭代器。
class Book:passclass BookCollection:def __init__(self):self.data = ['《往事》', '《只能》', '《回味》']self.cur = 0def __iter__(self):return self#for in調用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的返回值,而不是直接在函數內處理#接著上次執行的結果繼續執行下去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來進行判空操作

對象存在不一定是True

  • None永遠對應False
  • 自定義的對象和True和False是怎么對應的?
class Test():passtest = Test() if test:print('S') #S,不存在len和bool時默認trueclass Test1():def __len__(self):return 0test = Test1() if test:print('S') else:print('F') #F
  • __len__與__bool__內置方法
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

我!結!課!了!

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。