5.1 宣告和呼叫函式
5.1.1 函式定義
函式:指組織好的,可重復使用的,用來實作單一,或相關聯功能的代碼段,【一個工具,隨調隨用,函式一詞來源于數學,但編程中函式和數學中的函式有很大不同,編程中的函式在英文中也有很多的不同,函式是指將一組陳述句的集合通過一個名字(函式名)封裝起來,要執行這個函式,只需呼叫這個函式名即可.】
5.1.2 函式的作用
函式能提高應用的模塊性和代碼的重復利用率,【降級代碼冗余,增加代碼的復用性,提高開發效率,提高程式擴展性】
5.1.3 函式的宣告和呼叫
◆函式的兩個階段:定義階段,呼叫階段,
定義階段:只檢查函式體內代碼語法,不執行函式體內代碼,
呼叫階段:執行代碼,
◆自定義函式:
?可以使用def關鍵字來創建Python自定義函式,其基本語法結構如下:
def 函式名(引數串列)
函式體
函式名() #呼叫函式
?引數串列可以為空,即沒有引數,也可以包含單個引數、多個引數、默認引數、可變長引數、引數之間使用逗號分隔,
?函式中無引數:
def func()
函式體
func() #呼叫函式
def lily():
num=600
score=num/6
return score
print(lily())#輸出100.0
◆函式的三種呼叫方式
?在本模塊中呼叫
?if __name__ == '__main__': 主函式呼叫
主函式的解釋:
→if __name__ == '__main__': 是函式的入口,也稱為主函式 ,__name__ 是當前模塊名,當模塊被直接運行時模塊名為 __main__ ,這句話的意思就是,當模塊被直接運行時,以下代碼塊將被運行,當模塊是被匯入時,代碼塊不被運行,
→在平時讀代碼的時候,經常出現if __name__==‘__main__’,這是一個函式的主入口,__name__代表當前模塊的名稱,__main__代表被運行模塊的名稱,如果兩個模塊相等就運行,不相等就不運行,
——————————————————————————————————————————————————————————————
注意:以上兩種都是在本模塊的呼叫;如果調不了,就是命名的問題,不要和python中的命名一樣
……………………………………………………………………………………………………………………………………………………………………
?在其他模塊中呼叫
★注意:必須按照縮寫去寫函式(因為縮進不容易報錯,這是由于python用縮進代替其它編程語言的begin和and,python中的縮進決定了代碼的作用域)
【例】
?>def out():
print('這是我輸出的第二個陳述句')
out()#輸出這是我輸出的第二個陳述句
>from diaoyong import out
out()#輸出這是我輸出的第二個陳述句 這是我輸出的第二個陳述句
?>def out():
print('這是我輸出的第二個陳述句')
if __name__ == '__main__':
out()#輸出這是我輸出的第二個陳述句
>from diaoyong import out
out()#輸出這是我輸出的第二個陳述句
5.2 引數和回傳值
5.2.1 函式中引數定義
如果你希望函式是可以計算的,但計算的資料需要從外面傳進來,那么傳輸資料的介質就叫做引數,引數分為形參和實參:
形參:函式定義時括號內的引數 實參:函式呼叫時括號內的引數
◆形參相當于變數,實參相當于變數的值,
◆形參:只在被呼叫時,才分配記憶體單元,呼叫結束,立刻釋放所分配的記憶體,只在函式內部有效
◆實參:進行函式呼叫時,實參必須是確定的值,可以是常量、變數、運算式、函式,
5.2.2 函式中有單個引數
def test(name):
"""
:param name:#引數name
:return:
"""
print('我是上海'+name)
test('彭于晏') #呼叫函式,輸出我是上海彭于晏
5.2.3 函式中有多個引數
def test(name,age):
"""
:param name: 傳入的引數為姓名
:param age: 傳入的引數為年齡
:return:
"""
print('我是上海'+name+'今年'+age)
test('吳彥祖','18')#輸出我是上海吳彥祖今年18
5.2.4 函式定義時帶上默認引數(預設引數)
def test(name='周杰倫'):
print('我是上海'+name)
test()#輸出我是上海周杰倫【#呼叫函式未給默認引數傳新值,則函式使用默認值 】
def test(name='周杰倫'):
print('我是上海'+name)
test('成龍')#輸出我是上海成龍【除錯函式給默認引數傳新值,則函式使用新值】
★注意:當多種引數同時出現在函式中,默認引數要放在最后的位置
5.2.5 可變長引數
◆可變長定義:
定義一個可變長元組后,函式呼叫處可以給當前可變長形參賦予N個實參,如沒有定義是可變長元組:在函式呼叫處只能給對應形參對應個數的具體實參,
◆可變長引數中的可變長元組 "*"表示的是可變長元組
def test(*name):#*號表示多個引數
print(name)
test('北京','故宮','長城')#輸出('北京', '故宮', '長城')
◆可變長引數中的可變長字典 "**"表示的是可變長字典
def test(*value,**value1):
print(value)
print(value1)
dict={'name':'周杰倫','age':18}
test('周杰倫','吳彥祖',**dict)
#輸出('周杰倫', '吳彥祖'){'name': '周杰倫', 'age': 18}
★注意:當可變長元組和可變長字典同時出現時,默認將可變長字典放后面
★【拓展】可更改(mutable)與不可更改(immutable)物件
在 python 中,strings, tuples, 和 numbers 是不可更改的物件,而 list,dict 等則是可以修改的物件,
◆不可變型別:變數賦值 a=5 后再賦值 a=10,這里實際是新生成一個 int 值物件 10,再讓 a 指向它,而 5 被丟棄,不是改變a的值,相當于新生成了a,
◆可變型別:變數賦值 la=[1,2,3,4] 后再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了,
◆python 函式的引數傳遞:
?不可變型別:類似 c++ 的值傳遞,如整數、字串、元組,如fun(a),傳遞的只是a的值,沒有影響a物件本身,比如在 fun(a)內部修改a的值,只是修改另一個復制的物件,不會影響 a 本身,
?可變型別:類似 c++ 的參考傳遞,如串列,字典,如 fun(la),則是將 la 真正的傳過去,修改后fun外部的la也會受影響
注意:python 中一切都是物件,嚴格意義我們不能說值傳遞還是參考傳遞,我們應該說傳不可變物件和傳可變物件,
5.2.6 函式的變數和作用域
變數作用域:一個程式的所有的變數并不是在哪個位置都可以訪問的,訪問權限決定于這個變數是在哪里賦值的,變數的作用域決定了在哪一部分程式你可以訪問哪個特定的變數名稱,Python的作用域一共有4種,分別是:
?L (Local) 區域作用域 ?E (Enclosing) 閉包函式外的函式中
?G (Global) 全域作用域
?B (Built-in) 內置作用域(內置函式所在模塊的范圍)
★以 L –> E –> G –>B 的規則查找,即:在區域找不到,便會去區域外的區域找(例如閉包),再找不到就會去全域找,再者去內置中找,
◆在函式中也可以定義變數,在函式中定義的變數被稱之為區域變數,區域變數只在定義它的函式內部有效,【定義在函式內部的變數擁有一個區域作用域】
◆在函式體之外定義的變數,我們稱之為全域變數,【定義在函式外的擁有全域作用域】
◆區域變數只能在其被宣告的函式內部訪問,而全域變數可以在整個程式范圍內訪問,呼叫函式時,所有在函式內宣告的變數名稱都將被加入到作用域中,
【例】 num=400
def lily():
global num#把函式內區域變數變為全域變數,函式外的原變數失效,global只能在函式體內使用
num=200
sum=num+100
print(sum)
lily()
test=num
print(test)#輸出300 200
【例】num=400
def lily():
num=200
sum=num+100
print(sum)
lily()
test=num
print(test)#輸出300 40
【例】num=100#在函式體外的變數是全域變數
def lily():
num=200#定義在函式體內的變數為區域變數
print(num)
lily()#輸出200
5.2.7 函式的回傳值
◆Python中,用def陳述句創建函式時,可以用 return 陳述句指定應該回傳的值,該回傳值可以是任意型別,需要注意的是,return 陳述句在同一函式中可以出現多次,但只要有一個得到執行,就會直接結束函式的執行,
◆函式中,使用return陳述句的語法格式如下:
return [回傳值]
其中,回傳值引數可以指定,也可以省略不寫(將回傳空值 None),
?def lily():
num=600
score=num/6
return score#return能把結果回傳,但其后面的代碼不會被執行 print(lily())#輸出100.0
◆回傳值的作用
?在程式開發中,有時候會希望一個函式執行程式結束后,告訴呼叫者一個結果,以便呼叫者針對具體的結果做后續的處理,
?回傳值是函式完成作業后,最后給到呼叫者的一個結果,
?在函式中使用return關鍵字可以回傳結果,
?呼叫函式的一方可以使用變數來接收函式的回傳結果,
【例】需求:登錄銀行系統并顯示余額,有兩個功能第一個是登錄,第二個是登錄后顯示余額,先登錄然后根據登錄是否成功然后是否顯示余額,
[思路分析]:如果想查詢到余額,前提必須登錄,所以現在我們用兩個函式來處理,第一個函式實作登錄,第二個函式實作余額查詢,呼叫第一個函式得到的結果給第二個函式,然后第二個函式根據結果進行代碼處理,
def login():
name=input('賬號:')
if name=='admin':
pw=input('密碼:')
if pw=='123456':
print('登錄成功')
return ('登錄成功')
else:
print('密碼輸入錯誤')
else:
print('賬號輸入錯誤')
def rmb():
cx=login()
if cx=='登錄成功':
print('您的賬戶余額為99999999999')
else:
print('查詢余額失敗')
rmb() #輸出 賬號:admin 密碼:123456 登錄成功 您的賬戶余額為99999999999
5.3 python內置函式
5.3.1 format()函式
format()函式是一種格式化字串的函式,該函式增強了字串格式化的功能,
基本語法:是通過 {} 來代替以前的 %
◆不設定指定位置,按默認順序
str="{}{}".format("hello","kitty",'boy') print(str)
#輸出hellokitty
str="{}{}{}".format("hello","kitty",'boy') print(str)
#輸出hellokittyboy
◆設定指定索引位置格式化輸出
str='{0}{2}'.format('hello','kitty','boy') print(str)
#輸出helloboy
◆設定引數名稱格式化輸出
str='姓名:{name} 年齡:{age}'.format(name='kitty',age='18')
print(str)#輸出 姓名:kitty 年齡:18
◆對串列進行格式化
?list=['kitty',18]
str = '姓名:{0[0]} 年齡:{0[1]}'.format(list)
print(str)#輸出姓名:kitty 年齡:18
?list=['kitty',18]
list1=['tom',24]
str = '姓名:{1[0]} 年齡:{0[1]}'.format(list,list1)
print(str)#輸出 姓名:tom 年齡:18
★注意:大括號里面的0和1代表的是串列、中括號里面的0和1是串列元素對應的索引位
◆對字典進行格式化輸出, "**"表示可變長字典
?dict={'name':'kitty','age':'18'}
str = '姓名:{name} 年齡:{age}'.format(**dict)
print(str)#輸出 姓名:kitty 年齡:18
?dict={'name2':'kitty','age2':'18'}
dict1={'name1':'tom','age1':'24'}
str = '姓名:{name1} 年齡:{age2}'.format(**dict,**dict1)
print(str)#輸出 姓名:tom 年齡:18
5.3.2 zip()函式
◆zip()函式用于將可迭代的物件作為引數,將物件中對應的元素打包成一個個元組,然后回傳由這些元組組成的串列,如果各個迭代器的元素個數不一致,則回傳串列長度與最短的物件相同,
? list1=['kitty','tom','lily']
list2=['18','22','24']
list3=list(zip(list1,list2))
print(list3)#輸出[('kitty', '18'), ('tom', '22'), ('lily', '24')]
?list1=['kitty','tom','lily']
list2=['18','24']
list3=list(zip(list1,list2))
print(list3)#輸出[('kitty', '18'), ('tom', '24')]
?list1=['kitty','tom','lily']
list2=['18','24']
list3=dict(zip(list1,list2))
print(list3)#{'kitty': '18', 'tom': '24'}
5.3.3 open()函式
◆open() 函式用于打開一個檔案,創建一個 file 物件,接收兩個引數:檔案名(file)和模式(mode)
◆語法:open(file, mode),模式有r(只讀),w(寫入覆寫),a(寫入追加)
◆檔案打開模式:檔案句柄 = open('檔案路徑', '模式')
◆讀的模式: r(只讀) [默認]
?kitty=open('wps.txt','r',encoding='utf-8')
all=kitty.read()
print(all)#輸出Nice to meet you!!!
?kitty=open('wps.txt','r',encoding='utf-8')
all=kitty.read()#讀取檔案中所有內容回傳字串#輸出
Nice to meet you!!!
125466
kbkvh
all=kitty.readline() #讀取檔案中第一行內容
#輸出Nice to meet you!!!
all=kitty.readlines() #讀取檔案中所有內容回傳串列
#輸出['Nice to meet you!!!\n', '125466\n', 'kbkvh']
◆讀相關函式檔案中包含中文字符的解決方法
o = open(r'C:\aa.txt','r')
all = o.read()
print all.decode('gbk') #進行解碼為gbk編碼
◆路徑中包含中文字符的解決方法
path = unicode(r'C:\多測師\aa.txt',encoding='utf-8')
o = open(path,'r')
a = o.read()
print a
◆寫的模式:w(寫入覆寫)
注:python具有垃圾回識訓制,當執行write寫入操作時,無法確定是否會立即寫入檔案,為了提高寫入效率,首先會將資料放到緩沖區,只有當檔案已滿、呼叫flush或檔案關閉(內部執行flush)時,緩沖區才會寫入檔案,因此,原因是不能使用兩個不同的變數名稱,因為寫入操作從未真正發生在kitty.close()行之前使用相同的變數名‘作業’的原因是,當你重新系結kitty=open(filename)時,以前系結到wps.txt的檔案現在不在任何地方被參考,因此收集器將其洗掉,當檔案句柄被洗掉時,資料寫入檔案,因此你可以在以后讀取到它,
?kitty=open('wps.txt','w',encoding='utf-8')
kitty.write('你好,kitty')
kitty.writelines('\n很高興遇見你')
kitty.close()#關閉檔案 #輸出你好,kitty
很高興遇見你
?kitty=open('wps.txt','w',encoding='utf-8')
kitty.write('你好,kitty')
kitty.writelines('很高興遇見你\nNice to meet you')
kitty.close()#輸出你好,kitty很高興遇見你Nice to meet you
◆追加的模式:a(寫入追加)
kitty=open('wps.txt','a',encoding='utf-8')
kitty.write('\npython學習要靈活一點')
kitty.close()#輸出 你好,kitty很高興遇見你
Nice to meet you
python學習要靈活一點
◆open()函式擴展用法
with open("C:\\aa.txt", 'r')as f:
a = f.read()
b = f.readline()
c = f.readlines()
d = f.write()
e = f.writelines()
用with陳述句的好處,就是到達陳述句末尾時,會自動關閉檔案,即便出現例外,
【拓展】as的三種用法:
◆ with...as...
第一種是某些物件總是有固定的規律做事,使用with as陳述句,省去必須要做的事情
◆ 基本原理:with陳述句后面的物件,它的特殊方法__enter__會被自動呼叫,而__enter__方法回傳的物件會賦值給as后面定義的變數temp,當with as代碼體中的全部陳述句執行完畢,with后面的物件,它的特殊方法__exit__又會被自動呼叫
?和with結合使用,主要用于檔案的讀寫操作,省去了關閉檔案的麻煩,
?
1、內置函式open會回傳一個File物件
2、File物件的__enter__方法會被自動呼叫,且__enter__方法回傳是self,即File物件本身
3、__enter__方法回傳的物件,會被賦值給as后面定義的變數my_file中
4、接著with as方法體中的print()陳述句執行
5、執行結束后,File物件的__exit__方法會被自動呼叫
◆ 匯入模塊起別名
第二種是匯入模塊是對模塊進行重命名,也就是給模塊起一個別名,
?import numpy as np#匯入numpy整個模塊,并指定別名為np
◆ except結合使用
第三種是寫入例外,和except組合使用,將捕獲到的例外物件賦值給e,可查看例外,

★Python內置函式表
|
內置函式 |
||||
|
abs() |
divmod() |
input() |
open() |
staticmethod() |
|
all() |
enumerate() |
int() |
ord() |
str() |
|
any() |
eval() |
isinstance() |
pow() |
sum() |
|
basestring() |
execfile() |
issubclass() |
print() |
super() |
|
bin() |
file() |
iter() |
property() |
tuple() |
|
bool() |
filter() |
len() |
range() |
type() |
|
bytearray() |
float() |
list() |
raw_input() |
unichr() |
|
callable() |
format() |
locals() |
reduce() |
unicode() |
|
chr() |
frozenset() |
long() |
reload() |
vars() |
|
classmethod() |
getattr() |
map() |
repr() |
xrange() |
|
cmp() |
globals() |
max() |
reverse() |
zip() |
|
compile() |
hasattr() |
memoryview() |
round() |
__import__() |
|
complex() |
hash() |
min() |
set() |
|
|
delattr() |
help() |
next() |
setattr() |
|
|
dict() |
hex() |
object() |
slice() |
|
|
dir() |
id() |
oct() |
sorted() |
exec內置運算式 |
5.4 python中的模塊
5.4.1 模塊的定義
◆Python模塊(Module):是一個Python檔案,以.py 結尾,包含了
Python 物件定義和Python陳述句,
?模塊讓你能夠有邏輯地組織你的Python代碼段,把相關的代碼分配到一個模塊里能讓你的代碼更好用,更易懂,
?模塊能定義函式,類和變數,模塊里也能包含可執行的代碼,
包和目錄的區別:包和模塊都可以被匯入,但是不能只匯入目錄
?新建一個軟體包里面有一個默認的__init__.py.這個模塊來初始化這個包當前所有的內容,有__init__.py模塊的包才叫做包
?Python中分為內置模塊和自建模塊(我們自己創建的模塊)
5.4.2 模塊的呼叫和匯入
◆模塊的匯入
import陳述句
?模塊定義好后,可以使用import陳述句來引入模塊,語法如下:
import module1,module2.....moduleN
比如要參考模塊 time,就可以在檔案最開始的地方用import time 來引入,在呼叫time模塊中的函式時,必須這樣參考:
模塊名.函式名(如:time.sleep(2))
注意:一個模塊只會被匯入一次,不管你執行了多少次import,這樣可以防止匯入模塊被一遍又一遍地執行
?from....import * 匯入一個模塊中的所有專案,如匯入time模塊中的所有類、函式、變數等等,語法如下:
from time import *
?from....import...從模塊中匯入一個指定的部分到當前命名空間中,語法如下:
from modname import name1,name2...nameN
→要匯入time模塊的sleep函式,使用如下陳述句:
from time import sleep
→要匯入time模塊中的sleep函式并取別名,使用如下陳述句:
from time import sleep as s
5.4.3 常見的模塊
python中常見的模塊:time模塊、random模塊、hashlib模塊、os模塊、re模塊、string模塊、xlrd模塊、json模塊、sys模塊
5.4.3.1 Time模塊
◆時間戳
?時間戳是指格林威治時間 1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒) 起至現在的總秒數
?最早出現的 UNIX 作業系統考慮到計算機產生的年代和應用的時限綜合取了1970年1月1日作為 UNIX TIME 的紀元時間(開始時間)
◆Time模塊中常見的方法:
?time.time()#1970到現在經過的秒數
import time#匯入time模塊
print(time.time())#通過模塊把里面的函式進行呼叫
#輸出1660135212.766191
?time.ctime()#固定格式的當前時間
import time
print(time.ctime())
#輸出Wed Aug 10 21:15:44 2022
?time.sleep()#延時或休眠,單位是秒
import time
time.sleep(3)
print(1)
from time import sleep
sleep(3)
print (1)
from time import *
sleep(3)
print (1)
#執行緒等待三秒,輸出1
?time.localtime()
→當引數為默認值時,回傳本地當前時間的時間元組
import time
print(time.localtime())
#輸出time.struct_time(tm_year=2022, tm_mon=8, tm_mday=10, tm_hour=20, tm_min=45, tm_sec=7, tm_wday=2, tm_yday=222, tm_isdst=0)
→當輸入引數秒后,回傳的是1970年1月1日早上8點后+引數秒數后的時間
import time
print(time.localtime(60))#輸出time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=8, tm_min=1, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
?time.asctime()#轉換為asc碼顯示當前時間
import time
print(time.asctime())#輸出Wed Aug 10 20:51:09 2022
?time.strftime(str,str_fmt)#根據 str 的格式把時間字串決議為時間元組
import time
print(time.strftime('%Y-%m-%d-%H-%M-%S'))
#輸出2022-08-10-21-02-23
【拓展】python 中時間日期格式化符號:
%y 兩位數的年份表示(00-99) %Y 四位數的年份表示(000-9999)
%m 月份(01-12) %d 月內中的一天(0-31)
%H 24小時制小時數(0-23) %I 12小時制小時數(01-12)
%M 分鐘數(00=59) %S 秒(00-59)
%a 本地簡化星期名稱 %A 本地完整星期名稱
%b 本地簡化的月份名稱 %B 本地完整的月份名稱
%c 本地相應的日期表示和時間表示 %j 年內的一天(001-366)
%p 本地A.M.或P.M.的等價符
%U 一年中的星期數(00-53)星期天為星期的開始
%w 星期(0-6),星期天為星期的開始
%W 一年中的星期數(00-53)星期一為星期的開始
%x 本地相應的日期表示 %X 本地相應的時間表示
%Z 當前時區的名稱 %% %號本身
from time import time,sleep,ctime#匯入多個函式可以用逗號隔開
挎包匯入模塊 from modetest import hanshu#通過包名把里面的模塊匯入
5.4.3.2 random模塊
python中的random模塊:生成隨機浮點數、整數、字串,還可以隨機選擇串列序列中的一個元素random() 方法回傳隨機生成的一個實數,它在[0,1)范圍內,
◆random模塊中常見的方法:
?random.random() 回傳隨機生成的一個 [0,1) 范圍內的實數
import random
print(random.random())#該方法隨機生成0到1之間的隨機浮點數,能取到0但取不到1
?random.randint(x,y)
import random
print(random.randint(1,5))#隨機生成指定范圍內的一個整數型亂數,包括開始值與結束值
?random.randrange(a,b,step)
隨機生成一個 [a,b) 之間的一個整數,可以定義 step 步長,與range()用法類似
import random
print(random.randrange(1,3,2))#生成指定范圍內的奇數,不包括結束值
print(random.randrange(0,3,2))#生成指定范圍內的偶數,不包括結束值
?random.choice(a)
從 a 中隨機選擇一個元素,a 不能為空且 a 不能為字典
import random
print(random.choice('hrofl69'))#生成隨機字符
?random.sample(a,n)
import random
list=['1','3','5','7','9']
print(random.sample(list,3))#從list串列中隨機取3個隨機且獨立的元素
?random.shuffle( )
import random
list=['1','3','5','7','9']
random.shuffle(list)#洗牌,隨機生成串列
print(list)
注意:shuffle()是不能直接訪問的,需要匯入 random 模塊,然后通過 random 靜態物件呼叫該方法
練習:使用random模塊隨機生成手機號碼,開頭三位數字自定義
import random
def phonenum(startnum):
phone=str(startnum)
for i in range(8):
phone+=str(random.randint(0,9))
return phone
print('隨機電話號碼:'+phonenum(137))
#輸出隨機電話號碼:13776277368
import hashlib
def md5fun(string):
list1=[]
md5=hashlib.md5()#MD5加密
md5.update(string.encode('utf-8'))
list1.append(string)
list1.append(md5.hexdigest())
return list1
print('生成16進制字串為:{0[1]}'.format(md5fun(phonenum(137))))#生成16進制字串為:c53cb7f966bed2dd59e78dd3702e86b8
Hashlib.md5()#MD5加密
import hashlib
kitty=hashlib.md5()#通過hashlib模塊中MD5函式創建一個物件
kitty.update('123456'.encode('utf-8'))#通過MD5物件呼叫update函式對字串進行加密
print(kitty.hexdigest())#通過物件呼叫hexdigest函式生成一個16進制并且為32位的字串
#輸出e10adc3949ba59abbe56e057f20f883e
練習:用random模塊隨機生成6位數驗證碼
import string
import random
def yanzhengma(num):
strs = ''
for i in range(num):
strs += str(random.choice(string.digits + string.ascii_letters))
return strs
print('隨機驗證碼為:' + yanzhengma(6))
#輸出 隨機驗證碼為:Oeffv6
練習:通過md5加密演算法把隨機生成的6位數驗證碼進行加密回傳16進制的字串
import hashlib
def md5fun(string):
list1=[]
md5=hashlib.md5()
md5.update(string.encode('utf-8'))
list1.append(string)
list1.append(md5.hexdigest())
return list1
print('\n隨機字串:{0[0]}\n生成16進制字串為:{0[1]}'.format(md5fun(yanzhengma(6))))
輸出:生成16進制字串為:eeeb71171fe971d5321e27af133f5def
5.4.3.3 python中os模塊
os模塊提供了多數作業系統的功能介面函式,當os模塊被匯入后,它會自適應于不同的作業系統平臺,根據不同的平臺進行相應的操作,在python編程時,經常和檔案、目錄打交道,所以離不了os模塊,【os模塊可以幫助我們直接對作業系統進行操作,通過直接呼叫作業系統對可執行操作檔案、命令,直接操作檔案,目錄等】
import os
os.system('chcp 65001')#命令提示符中的一個可執行命令,可以回傳活動代碼頁對編碼,還可以設定當前對活動代碼頁
os.system('ping www.baidu.com')#執行cmd命令
os.system('xxx.html')#默認瀏覽器打開xxx.html檔案
os.system('xxx.exe')#運行exe程式
os.system('xxx.py -u http:1.1.1.1')#運行python腳本
os模塊中常見的方法:
os.getcwd()獲取當前執行命令所在目錄
os.path.isfile()判斷是否為檔案
print(os.path.isfile(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))#輸出False
os.path.isdir() #判斷是否為目錄
print(os.path.isdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))
#輸出True
os.path.exists() #判斷檔案或目錄是否存在
★(重要)os.listdir(dirname) #列出指定目錄下的目錄或檔案
print(os.listdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))
#輸出['hanshu.py', 'wps.txt', '__init__.py', '__pycache__']
os.path.split(name) #分割檔案名與目錄
print(os.path.split(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))#輸出('C:\\Users\\Administrator\\PycharmProjects\\pythonProject', 'modetest')
os.path.join(path,name) #連接目錄與檔案名或目錄
print(os.path.join('C:\\Users\\Administrator\\PycharmProjects\\pythonProject', 'modetest'))#輸出C:\Users\Administrator\PycharmProjects\pythonProject\modetest
os.mkdir(dir) #創建一個目錄
os.mkdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\mulu')
os.rename(old,new) #更改目錄名稱
os.rename(r'C:\Users\Administrator\PycharmProjects\pythonProject\Azhengze',r'C:\Users\Administrator\PycharmProjects\pythonProject\mulu')
5.4.3.4 python中re正則模塊
實作一個編譯查找,一般在日志處理或者檔案處理時用的比較多
正則運算式主要用于模式匹配和替換作業,
預定義字符集匹配:
\d:數字0-9
import re
str=re.match('\d','123434hhjash')
print(str)輸出<re.Match object; span=(0, 1), match='1'>
str=re.match('\d','a123434hhjash')
print(str)#輸出None(匹配失敗)
\D:非數字
\s:空白字符
\n:換行符
\r:回車符
re模塊數量詞匹配:
符號^:表示的匹配字符以什么開頭
符號$:表示的匹配字符以什么結尾
符號*:匹配*前面的字符0次或n次
str=re.match('\d*','123434hhjash')
print(str)#輸出<re.Match object; span=(0, 6), match='123434'>
str=re.match('\d*','m123434hhjash')
print(str)#輸出<re.Match object; span=(0, 0), match=''>
eg:ab* 能匹配a 匹配ab 匹配abb
符號+:匹配+前面的字符1次或n次
str=re.match('\d+','123434hhjash')
print(str)#輸出<re.Match object; span=(0, 6), match='123434'>
符號?:匹配?前面的字符0次或1次
str=re.match('\d?','123434hhjash')
print(str)#輸出<re.Match object; span=(0, 1), match='1'>
str=re.match('\d?','a123434hhjash')
print(str)#輸出<re.Match object; span=(0, 0), match=''>
符號{m}:匹配前一個字符m次
str=re.match('\d{2}','123434hhjash')
print(str)#輸出<re.Match object; span=(0, 2), match='12'>
符號{m,n}:匹配前一個字符m到n次(包括n次),m或n可以省略,m、n都是正整數
str=re.match('\d{2,6}','123434hhjash')
print(str)#輸出<re.Match object; span=(0, 6), match='123434'>
5.4.4 re模塊相關函式
5.4.4.1 match
從第一個字符開始匹配,如果第一個字符不是要匹配的型別、則匹配失敗并報錯
?str=re.match('^2\d{2}','23434hhjash')
print(str)#輸出<re.Match object; span=(0, 3), match='234'>
?str=re.match('^2\d{2}','123434hhjash')
print(str)#輸出None
?str=re.match('^2\D{1,3}','2hhjash')
print(str)#輸出<re.Match object; span=(0, 4), match='2hhj'>
?str=re.match('^2\D{1,3}$','2hhj')#要求字串位數要與1,3對應,位數若多或少會報錯為none
print(str)#輸出<re.Match object; span=(0, 4), match='2hhj'>
?str=re.match('^1[38675][13586]\d{8}$','15366668888')
print(str)#輸出<re.Match object; span=(0, 11), match='15366668888'>
?str=re.match('^1[a-z][A-Z]\d{8}$','1aA88886666')
print(str)#輸出<re.Match object; span=(0, 11), match='1aA88886666'>
注意:如果規則帶了'+',則匹配1次或者多次,無'+'只匹配一次
5.4.4.2 search
從第一個字符開始查找、一找到就回傳第一個字串,找到就不往下找,找不到則報錯
?str=re.search('\d','2664ewhsjuf15sd')
print(str.group())#輸出2
?str=re.search('\d+','w2664ewhsjuf15sd')
print(str.group())#輸出2664
?str=re.search('\d+','wewhsjuf15sd')
print(str.group())#報錯AttributeError: 'NoneType' object has no attribute 'group'
?str=re.search('\d*','2664ewhsjuf15sd')
print(str.group())#輸出2664
?str=re.search('\d*','w2664ewhsjuf15sd')
print(str.group())#無回傳值,第一個必須是整型數字
5.4.4.3 findall
從第一個字符開始查找,找到全部相關匹配為止,找不到回傳一個串列[]
?str=re.findall('\d+','o2664ewhsjuf15sd')
print(str)#輸出['2664', '15']
?str=re.findall('\D+','o2664ewhsjuf15sd')
print(str)#輸出['o', 'ewhsjuf', 'sd']
?str=re.findall('error','o2664ewherror15sd$')
print(str)#輸出['error']【可用于查找關鍵字】
?str=re.findall('error(.+)error','erroro2664ewherror15sderror$')#查找以error開頭,以error結尾的中間部分
print(str)#輸出['o2664ewherror15sd']【.表示任意字符但使用換行符,換行符后面將不會被匹配 +表示匹配1次或多次】
?str=re.findall('error(.+)error','erroro2664ewherror15s\nderror$')
print(str)#輸出['o2664ewh']
?str = re.findall('python','kitty')
print(str)#無匹配項時,輸出空串列[]
5.4.4.4 compile
編譯模式生成物件,找到全部相關匹配為止,找不到回傳一個串列[]
?str=re.compile('error')#需要查找出的物件
str2=str.findall('4146aajerror$%54errorfgg')#定義在哪找
print(str2)#輸出['error', 'error']
5.4.5 【模塊練習】
?使用os模塊寫一個遞回列印出一級目錄下面所有的絕對路徑
import os
def get_path(path):
kitty=os.listdir(path)
# print(kitty)
for i in kitty:
newpath=os.path.join(path, i)#對檔案和目錄進行拼接后讀取檔案絕對路徑
if os.path.exists(newpath): #通過讀取絕對路徑判斷newpath是否為一個檔案
print(newpath)
else:
get_path(newpath)#此處是遞回函式,在函式中呼叫自己
get_path(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest')#獲取目錄
#輸出C:\Users\Administrator\PycharmProjects\pythonProject\modetest\hanshu.py
C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt
C:\Users\Administrator\PycharmProjects\pythonProject\modetest\__init__.py
C:\Users\Administrator\PycharmProjects\pythonProject\modetest\__pycache__
?用正則方法實作統計檔案指定字符所在行的數量,如“實作”所在行出現多少次(檔案中的“實作”)
import re
def count(path):
kitty=open(path,'r')
hello=kitty.readlines()
num=0
for i in hello:
tom=re.findall('kitty',i)
#第一種方法
for j in set(tom):
num+=1
print(num)
第二中方法
if 'kitty' in tom:
num+=1
print(num)
count(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt')#輸出2
?用正則實作寫一段代碼統計檔案中的例如error和waring單詞它們分別出現的次數
方法一★import re
def count(path):
kitty=open(path,'r',encoding='utf-8')#定義物件并打開檔案,只讀
hello=kitty.readlines()#讀取所有行
dict1={}
for i in hello:#遍歷出一個i
tom=re.findall('error',i)#從i中找error
lily=re.findall('waring',i)#從i中找waring
for j in tom:
dict1[j]=dict1[j]+1 if j in dict1 else dict1.setdefault(j,1)
for k in lily:
dict1[k]=dict1[k]+1 if k in dict1 else dict1.setdefault(k,1)
print(dict1)
count(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt')
#輸出{'error': 3, 'waring': 2}
方法二★import re
fileurl=r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt'
liststr=['error','warning']
def filelistcount(url,strlist):
with open(url,'r',encoding='utf-8') as file:
count=0
dicstr={}
allline=file.read()
print(file.read())
for i in set(strlist):
str1=re.findall(i,allline)
dicstr.setdefault(i,len(str1))
print(dicstr)
filelistcount(fileurl,liststr)
#輸出{'warning': 0, 'error': 3}
?用正則完成市面上手機號碼撰寫規則,隨機生成11位數,然后通過正則匹配出符合規則的11位手機號碼
import random,string,re
def get_phone():
num=string.digits
list=[]
for i in range(11):
list.append(random.choice(num))#隨機選取數字
hello=''.join(list)
kitty=re.findall('^1[34578][12689]\d{8}$',hello)
if kitty:
print(''.join(kitty))
else:
get_phone()
get_phone()#輸出18203964603
Python 3 轉義字符表(帶示例)
5.5 python中的物件
5.5.1 面向物件的基本概念
◆面向物件思想
?面向物件編程是在面向程序編程的基礎上發展來的,它比面向程序編程具有更強的靈活性和擴展性,
?面向物件編程(Object-oriented Programming,簡稱 OOP),是一種封裝代碼的方法,其實,在前面章節的學習中,我們已經接觸了封裝
?代碼封裝,其實就是隱藏實作功能的具體代碼,僅留給用戶使用的介面,就好像使用計算機,用戶只需要使用鍵盤、滑鼠就可以實作一些功能,而根本不需要知道其內部是如何作業的,
?面向物件編程,也是一種封裝的思想,它可以更好地模擬真實世界里的事物(將其視為物件),并把描述特征的資料和代碼塊(函式)封裝到一起,
◆面向物件(Object Oriented)是軟體開發方法,一種編程范式,【是一種編程思想,任何事物都可作為一個物件,都一個對應的屬性和行為】最重要的概念是類和實體
◆范式從本質上講是一種理論體系、理論框架,
◆類(class): 用來描述具有相同的屬性和方法的物件的集合,它定義了該集合中每個物件所共有的屬性和方法,物件是類的實體,
◆實體(instance):類是一個具體的物件,創建出來的物件稱為實體(即實際的物件),
◆實體化:創建一個類的實體,類的具體物件,【根據一個類創建不同物件的動作,稱為實體化】
◆實體屬性:物件的屬性
◆實體變數:在類的宣告中,屬性是用變數來表示的,這種變數就稱為實體變數,實體變數就是一個用 self 修飾的變數,【物件或實體獨有的屬性】
◆實體方法:物件呼叫的方法
★類(Class)和實體(Instance)的區別:類是抽象的模板,比如Student類,而實體是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同,
◆物件(object):通過類定義的資料結構實體,物件是類的實體,物件就是看得見、摸得著的東西,有自己的特征,也可能有自己的行為,萬物皆可物件,物件包括兩個資料成員(類變數和實體變數)和方法,
★物件和類的關系:類和物件的關系就像模具和鑄件的關系,類的實體化的結果就是物件,而物件的抽象體就是類,
◆屬性:類中的所有變數稱為屬性,屬性稱為變數:如lily=‘123’
◆方法:類中的所有定義的函式稱為方法,與函式所有不同的是,類方法至少要包含一個 self 引數,類方法無法單獨使用,只能和類的物件一起使用,
◆類變數:類變數在整個實體化的物件中是公用的,類變數定義在類中且在函式體之外,類變數通常不作為實體變數使用,【即類共有的屬性】
◆繼承:即一個派生類(derived class)繼承基類(base class)的欄位和方法,繼承也允許把一個派生類的物件作為一個基類物件對待,
例如,有這樣一個設計:一個Dog型別的物件派生自Animal類,這是模擬"是一個(is-a)"關系(例圖,Dog是一個Animal),
◆方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個程序叫方法的覆寫(override),也稱為方法的重寫,
5.5.2 定義和使用類
5.5.2.1 類的定義
◆類的設計:在使用面向物件開發前,應該首先分析需求,確定程式中包含哪些內容,
在程式開發中,設計一個類,通常要滿足以下三個條件:一是類名,即這類事物的名字,需滿足大駝峰命名法;二是屬性,即這類事物具有什么樣的特征;三是方法,即這類事物具有什么樣的行為,
大駝峰命名法:每個單詞的首字母大寫,且單詞與單詞之間沒有下劃線
◆類名的確定:一般采用名詞提煉法分析整個業務流程,出現的名詞通常就是要找的類
★類名稱定義規范:
?不要以純數字命名
?不要以python中保留字符(關鍵字)來命名
?不要以檔案名命名 ?不能出現特殊字符
?要簡短且見名知義
?當類名稱中有多個單詞時,應采用大駝峰命名法
◆屬性和方法的確定:對物件的特征描述,通常可以定義為屬性;對于物件具有的行為(動詞),通常可以定義為方法,
★注意:若需求中沒有涉及到的屬性或方法,在設計類時,一般不需要考慮屬性和方法
◆定義簡單的類(只包含方法)
面向物件實質是更大的封裝,在一個類中封裝多個方法,這樣通過這個類創建出來的物件,就可以直接呼叫這些方法了
定義只包含方法的類:在python中定義一個只包含方法的類,基本語法如下:
class 類名:
def 方法1(self,引數串列):
pass
def 方法2(self, 引數串列):
pass
方法的定義格式和之前學過的函式拒戶一樣,區別在于第一個引數必須是self
◆創建物件:物件是類的實體,只有在類中定義了物件才能使用類,當定義完成后,要使用這個類來創建物件,創建物件基本格式如下:
物件變數=類名()
【例】面向物件程式:小貓愛吃魚,小貓要喝水
class Cat:#定義一個類
def eat(self):#定義方法1
print('小貓愛吃魚')
def drink(self):#定義方法2
print('小貓要喝水')
tom=Cat()#把Cat()類創建為一個tom物件
tom.eat()#小貓愛吃魚#呼叫tom物件里的eat方法
tom.drink()#小貓要喝水#呼叫tom物件里的drink方法
◆python中給物件設定屬性:
▼tom.name=’Tom’#但不推薦使用此種方法,因為物件的屬性應該封裝在類的內部只要在類的外部的代碼中直接通過,設定一個屬性即可,
class Cat:
def eat(self):
print('%s愛吃魚' %self.name)
tom=Cat()
tom.name='Tom' #實體變數
tom.eat() #Tom愛吃魚
lily=Cat()
lily.name='大熊貓'
lily.eat()#大熊貓愛吃魚
▼標準定義方法:
【例】#object稱為父類或基類,也是一切類的父類,類中定義一個方法時按tab鍵自動定位合適撰寫位置
#表示該類從哪個類繼承下來的,object是所有類都會繼承的類
class People(object):#經典類
# (定義變數)類變數
head=1
#建構式,又稱構造方法,此處稱為構造方法,作用是為了創建形式物件,雙下劃線表示私有方法,name、age是形式引數
def __init__(self,name,age):
# self.name、self.age稱為實體變數,self是當前類的物件本身,私有變數,只能在內部使用
self.name = name#實體變數
self.age = age
#呼叫實體變數
# print('name')#輸出name
#這是實體方法
def play(self):
print(self.name+'去打籃球')
#如何呼叫,需要先實體化創建一個物件lily,物件的名字叫kitty
lily=People('kitty',22)#創建一個物件lily
tom=People('hello',24)
#呼叫類方法
lily.play()#輸出kitty去打籃球
tom.play()#輸出hello去打籃球
#呼叫類變數
print(People.head)#輸出1
▼初始化方法
當使用類名()創建物件時,會自動執行操作,例如為物件在記憶體中分配空間---創建物件,為物件的屬性設定初始值——初始化方法是__init__,是物件的內置方法,主要用來定義一個類具有哪種屬性的方法,
由于類可以起到模板的作用,因此在創建實體的時候,可把我們認為必須要系結的屬性強制填進去,此時可用python的內置方法__init__
注意:
?定義類的時候__init__是一個建構式,該函式是兩個下劃線開頭和兩個下劃線結束,其作用就是當創建類的物件和實體時系統會自動呼叫建構式,通過建構式對類進行初始化操作,
?在創建實體的時候,就不能傳入空的引數,必須傳入與__init__方法匹配的引數
?定義類的時候__init__方法中有一個引數self,這也是類中的方法與普通函式的區別,類的中的方法必須有一個引數self,而且位于引數串列的開頭,在類中self就是代表類的當前類的實體(物件)自身,在python呼叫時不用傳遞該引數,即無需傳值,python會將物件自動傳給self接受
在初始化方法內部定義屬性,即在__int__方法內部使用self.屬性名=屬性的初始值來定義屬性,定義屬性之后,再使用Cat創建的物件,都會擁有該屬性,
例:在Cat類,把name\colour等屬性綁上去
class Cat(object):
#在定義屬性時,不設定初始值時,可設關鍵字為None,表示無,即一個空物件,沒有方法和屬性,是一個特殊的常量,并可將None復制給任何一個變數
def __init__(self,name,colour):
self.name = name
self.colour = colour
lily=Cat('tom',None)
print(lily.name)#輸出tom
print(lily.colour)#輸出None
一個物件的屬性可以是另一個類創建時的物件,例如
class Tom():
def __init__(self,model):
self.model = model
self.bull_count = 0
def add_bullet(self,count):
self.bull_count+=count
def shoot(self):
if self.bull_count<=0:
print('[%s]祝你生日快樂!!!'%self.model)
return
self.bull_count -= 1
print('[%s]哼哈哼哼哈哈,,[%d]'%(self.model,self.bull_count))
class Masike():
def __init__(self, name):
self.name=name
self.Tom=None
def fire(self):
if self.Tom == None:
print('[%s]去三亞旅游'%self.name)
return
print('沖啊,,,[%s]'%self.name)
self.Tom.add_bullet(50)
self.Tom.shoot()
hello=Tom('AK47')
kitty=Masike('Ak47')
kitty.Tom=hello
kitty.fire()
print(kitty.Tom)
#輸出沖啊,,,[Ak47]
[AK47]哼哈哼哼哈哈,,[49]
<__main__.Tom object at 0x0000025275BA3EE0>
5.5.2.2 類的使用
◆類的封裝/呼叫
封裝是面向物件編程的一大特性, 我們在使用面向物件開發程式的時候, 第一步就應該現在需求分析, 然后根據明確的職責把不同的屬性和方法封裝到一個又一個抽象的類中, 之所以說是抽象, 因為在程式開發中, 類是不能直接使用的,當我們定義好了一個類之后, 就可以在類的代碼外部, 使用定義到的類創建出一個又一個物件, 讓這些物件來呼叫我們封裝在類的內部的方法, 這個是面向物件編程的一個非常明顯的特點,(在外部,類創建物件, 物件呼叫方法)
物件的方法的實作細節都是封裝在類的內部的,
看到需求, 應該使用名詞提煉法, 把需求中的名詞提煉出來, 有小明, 就可以定義一個 Person() 類, 在Person() 類增加一個name的屬性, 讓這個name屬性來記錄一下小明的名字,體重是小明的一個特征, 因此我們再需要定義一個體重weight 的屬性, 讓weight 來記錄小明的體重
?呼叫類下的方法,必需通過類的的實體/類名()進行呼叫
? 當類中初始化方法__init__中存在引數時,則在實體化時,需要往實體括號中傳入引數
?當類中無初始化方法或者__init__中不存在引數時,則在實體化時,不需要往實體括號中傳入引數,而在呼叫方法時再進行傳參
◆類的作用
?定義變數;
?創建物件;
?派生子類;
◆面向物件和面向程序
面向物件開發步驟如下:
1、使用面向物件開發,第1步是設計類,并使用類名()創建物件,創建物件的動作有兩步:①在記憶體中為物件分配空間;②呼叫初始化方法__init__為物件初始化;
2、創建物件后,記憶體中就有了一個物件且實實在在的存在,即實體(創建出來的物件叫做類的實體;創建物件的動作叫做實體化;物件的屬性叫做實體屬性;物件呼叫的方法叫做實體方法)
?面向程序優缺點:
優點:流程化,分步驟實作,效率高,代碼短小精悍
缺點:思考難道大,代碼復用率低,擴展差,難維護
?面向物件優缺點:
優點:結構化,模塊化,易擴展,可繼承,可覆寫,易維護
缺點:程式臃腫,性能低
◆類物件和實體物件
類是一個特殊的物件,python中一切皆物件,如
class AA: 定義的類屬于類物件,
class AA():定義的類屬于實體物件,
在python中,類是一個特殊的物件,即類物件,在程式運行時,類同樣會被加載到記憶體,類物件在記憶體中只有一份,使用一個類可以創建出多個物件實體,除了封裝實體的屬性和方法外,類物件還可以擁有自己的屬性和方法(類屬性:類方法),通過 類名. 的方式訪問類的屬性或者呼叫類的方法,
在程式執行時,物件各自擁有自己的實體屬性,呼叫物件方法,可以通過self. 訪問自己的屬性并呼叫自己的方法
?結論:每一個物件都有自己獨立的記憶體空間,保存各自不同的屬性,多個物件的方法,在記憶體中只有一份,在呼叫方法時,需要把物件的參考傳遞到方法內部
◆類中的類變數、實體變數
在整個類里面有的屬于類的,有的屬于物件的,那么屬于類的屬性叫類變數,屬于物件的屬性叫做實體變數,
class People(object):
head = 1 #類變數
def __init__(self,name):
self.name = name #實體變數
p = People('xiaowang')#創建物件
◆類屬性和實體屬性
類屬性:指標對類物件定義的屬性(類屬性作用:通常用來記錄與這個類相關的特征,但不會用于記錄具體物件的特征,一般在class關鍵字下方定義類屬性)
例:需求是定義一個工具類,每件工具都有自己的name,統計類創建工具(實體物件)的數量?
class Tool(object):
#定義變數count接收創建工具(物件)的總數
count = 0
def __init__(self,name):
self.name = name
#針對類屬性做一個計數+1
Tool.count+=1
#創建工具(即實體物件)
tool1=Tool('刀')
tool2=Tool('斧子')
tool3 = Tool('鐮刀')
tool4 = Tool('<empty>')
#列印計數
print('現在創建了%d把工具'%Tool.count)
◆類中的實體方法、動態方法、靜態方法
★類方法:指標對類物件定義的方法(類方法作用:在類方法內部可以直接訪問類屬性或者呼叫其它的類方法)
語法如下: @classmethod
def 類方法名(cls):
pass
類方法需要用到修飾器@classmethod來標識,告訴解釋器這是一個類方法,類方法的第一個引數是cls指由哪一個類呼叫的方法,方法內的cls指哪一個類的參考,這個引數與實體方法的第一個引數self類似,
類方法通過類名呼叫,呼叫類方法時不需要傳遞cls引數,在方法內部可以通過cls. 訪問當前類的屬性,也可以通過cls. 呼叫當前類的其它的類方法
修飾器:不會改變原有代碼結構并增加額外的功能
呼叫:類名+方法名
【例】定義一個工具類,每件工具都有自己的name,在類中封裝一個nasa.tool的類方法,輸出使用當前的這個類以及創建物件的個數
class Tool(object):
#定義變數count接收創建工具(物件)的總數
count = 0
def __init__(self,name):
self.name = name
#針對類屬性做一個計數+1
Tool.count+=1
@classmethod
def tool_count(cls):
print('現在創建了%d個工具' % cls.count)
#創建工具(即實體物件)
tool1=Tool('刀')
tool2=Tool('斧子')
tool3 = Tool('鐮刀')
tool4 = Tool('<empty>')
#列印計數
Tool.tool_count()
class Dragon(object):
dog_count=0
@staticmethod
def run():
#當print列印時不需要訪問實體屬性也不需要訪問類屬性的方法
print('龍在飛!!!')
def __init__(self,name):
self.name=name
Dragon.run()
@叫做修飾器,裝飾器的作用是為了不影響原有的功能基礎上給原有的方法增添新的方法的功能
靜態方法:方法前加了@staticmethod識別符號,則稱為靜態方法,反之為實體方法,靜態方法為類所用,可以通過物件來使用,也可通過類來使用,但一般常通過類名使用,這是因為靜態方法只需要定義類,不必建立實體就可以直接使用,靜態方法只能呼叫靜態變數,
……………………………………………………………………………………………………………………………………………………………………
【例】需求:設計一個類,定義一個類屬性記錄游戲的歷史最高分,定義一個實體屬性記錄當前游戲的玩家姓名;再定義一個靜態方法顯示游戲幫助資訊,定義一個類方法顯示歷史記錄,定義一個實體方法開始當前玩家的游戲,主程式步驟:1、查看游戲幫助2、查看歷史最高分3、創建游戲物件,開始游戲4、游戲結束,查看游戲最高分
class Game(object):
#類屬性,游戲最高分
top_score=0
#實體屬性,玩家姓名
def __init__(self,player_name):
self.player_name=player_name
#靜態方法,顯示幫助資訊
@staticmethod#靜態方法
def show_help():
print('幫助資訊:選擇一名人物作為你的第一個英雄,開始游戲')
#類方法,顯示歷史記錄,最高分
@classmethod#類方法
def show_top_score(cls):
print('游戲最高分是%d'%cls.top_score)
#創建實體方法,開始游戲
def start_game(self):
print('提示:玩家[%s]開始游戲!!!'%self.player_name)
#使用類名修改歷史最高分
Game.top_score=999
#1.查看游戲幫助
Game.show_help()#輸出 幫助資訊:選擇一名人物作為你的第一個英雄,開始游戲
#2、查看歷史最高分
Game.show_top_score()#輸出 游戲最高分是0
#3、創建游戲物件,開始游戲
game=Game('kangkang')
game.start_game()#輸出 提示:玩家[kangkang]開始游戲!!!
#4、游戲結束,查看游戲最高分
Game.show_top_score()#輸出 游戲最高分是999
……………………………………………………………………………………………………………………………………………………………………
【例】
class People(object):
def __init__(self,name):
self.name = name #實體變數
def play(self): #實體方法
print(self.name + '打籃球')
p = People('xiaowang')#創建物件
People.play() #類呼叫實體方法
p.play() #物件呼叫實體方法#類方法
@classmethod
def func1(cls):
cls.name1 = '我是一個類方法' #定義一個類變數
print (cls.name1)
#靜態方法
@staticmethod
def func2():
print ('我是一個靜態方法')
◆Python 中的實體方法、類方法、靜態方法的區別:
1、關于引數的區別
實體方法:定義實體方法是最少有一個形參 ---> 實體物件,通常用self
類方法:定義類方法的時候最少有一個形參 ---> 類物件,通常用cls
靜態方法:定義靜態方法的時候可以不定義形參
2、關于方法定義時候添加裝飾器的區別
實體方法:不需要添加裝飾器
類方法:需要添加裝飾器 ----> @classmethod
靜態方法:需要添加裝飾器 ---> @staticmethod
3、呼叫:
1.實體方法可以通過物件直接呼叫
2.但是用類名呼叫的時候,需要創建一個物件,并且在傳遞引數的時候要將物件傳遞進去
3.類方法可以通過類名直接呼叫,也可以通過物件來呼叫
4.靜態方法可以通過類名直接呼叫,也可以通過物件來呼叫
4、訪問物件的區別
實體方法在方法內部需要訪問實體屬性(實體方法的內部可以使用 類名. 格式訪問類屬性)
類方法在方法內部只需要訪問類屬性
靜態方法在方法內部不需要訪問實體屬性和類屬性
【問】若方法內部既要訪問實體屬性又要訪問類屬性,應該定義什么方法?
實體方法,因為類只有一個,在實體方法的內部可以使用類名訪問屬性
5、補充
1.靜態方法不可以繼承
2.類方法不能訪問實體變數,只能訪問類變數
5.5.3 補充
5.5.3.1 __del__方法
◆在python中當使用類名()創建物件時,為物件分配完空間后,自動呼叫__init__方法.當一個物件被從記憶體中銷毀前,會自動呼叫__del__方法
◆應用場景:__init__改造初始化方法,可以讓創建物件更加靈活
__del__如果希望在物件被銷毀前,再做一些事情,可以使用__del__方法
◆生命周期:一個物件從呼叫類名()創建,生命周期開始;一個物件的__del__方法一旦被呼叫,生命周期結束,在物件的生命周期內,可以訪問物件屬性或者讓物件呼叫方法,
class Cat:
def __init__(self,new_name):
self.name=new_name
print('%s來了'%self.name)
def __del__(self):
print('%s去了'%self.name)
#tom是一個全域變數
tom=Cat('Tom')
print(tom.name)
#del關鍵字可以洗掉一個物件
del tom
print('-'*50)#列印符號“-”50個
print(tom.name)
5.5.3.2 __str__方法(重要)
◆在python中,使用print輸出物件變數,默認情況下,會傳出這個變數參考的物件是由哪一類創建的物件,以及在記憶體中的地址(十六進制表示),如果希望使用print輸出物件變數時,能夠自定義列印自定義的內容,就可以使用__str__內置方法
注意:__str__方法必須回傳一個字串
class Cat:
def __init__(self,new_name):
self.name=new_name
print('%s來了'%self.name)
def __del__(self):
print('%s去了'%self.name)
def __str__(self):
return '我是小貓[%s]'%self.name
tom=Cat('Tom')
print(tom)
#輸出 Tom來了
我是小貓[Tom]
Tom去了
5.5.3.3 身份運算子
◆身份運算子:用于比較兩個物件的記憶體地址是否一致,是否是對同一個物件的參考.在Python中針對None進行比較時,建議使用is判斷,
is:用來判斷兩個識別符號是不是參考同一個物件(x is y 類似 id(x)==id(y))
is not:判斷兩個識別符號是不是參考不同物件(x is not y 類似 id(a)!=id(b))
is與==的區別
is用于判斷兩個變數的參考物件是否為同一個
==用于判斷參考變數的值是否相等
5.5.3.4 私有屬性和私有方法
◆私有屬性和私有方法應用場景:在實際開發中,物件的某些屬性或方法可能只希望在物件內部被使用,而不希望在外部被訪問到,
◆私有屬性:物件不希望公開的屬性
◆私有方法:物件不希望公開的方法
◆在屬性名或者方法名前增加兩個下劃線,這種形式的定義就是私有屬性或私有方法,
◆在物件的內部,是可以訪問物件的私有屬性和方法的,在物件的外部,不能訪問物件的私有屬性和方法
【在物件的外部】
例
class Women:
def __init__(self,name):
self.name = name
#不能訪問年齡
self.__age=18
def secret(self):
print('我的年齡是%d'%self.__age)
lily=Women('xiaoqiao')
lily.secret()#輸出 我的年齡是18
例
class Women:
def __init__(self,name):
self.name = name
#不能訪問年齡
self.__age=18
def secret(self):
#在物件方法內部可以訪問物件私有屬性
print('%s年齡是%d'%(self.name,self.__age))
lily=Women('xiaoqiao')
print(lily.age)#呼叫屬性,輸出18
lily.__secret()#外部不能直接訪問或呼叫私有屬性
lily.secret()#呼叫方法輸出xiaoqiao年齡是18
◆偽私有屬性和方法(科普)
注意:在日常開發中,不要使用該方式訪問物件的私有屬性或私有方法,
結論:python中并沒有真正意義上的私有,在給屬性、方法命名時,實際上是對名稱做的一些特殊處理,使得外界無法訪問,處理方式是在名稱前加_類名即_類名__名稱
【例】
class Women:
def __init__(self,name):
self.name = name
#不能訪問年齡
self.__age=18
def secret(self):
print('%s年齡是%d'%(self.name,self.__age))
lily=Women('xiaoqiao')
#私有屬性,外部不能直接訪問,但可以通過‘_類名__名稱’訪問
print(lily._Women__age)#輸出18
#私有方法,外部不能直接訪問,但可以通過‘_類名__名稱’訪問
lily._Women__secret()#輸出xiaoqiao年齡是18
5.5.3.5(拓展) 列舉值
起初python中并未內置列舉(Enumerate)(enum)型別,列舉是在python3.4中添加的新功能(3.4版本前可以使用列舉,但需要下載插件pip install enum安裝使用,3.4后不需要下載插件可直接使用)
◆列舉定義:指一系列符號名稱的集合,集合中每個元素要保證唯一性和不可變性,
因此我們可以對列舉中的元素進行恒等比較,通俗來講列舉是一系列常量對集合,是可迭代的,
【例】 from enum import Enum
class DragonColor(Enum):
Mon='red'
Tue='yellow'
Wed='black'
Thu='black'
Fri='white'
#訪問列舉成員
print(DragonColor.Mon)#輸出 DragonColor.Mon
#列舉成員名稱
print(DragonColor.Mon.name)#輸出 Mon
#列舉成員值
print(DragonColor.Mon.value)#輸出 red
……………………………………………………………………………………………………………………………………………………………………
列舉迭代: from enum import Enum
class DragonColor(Enum):
Mon='red'
Tue='yellow'
Wed='black'
Thu='pink'
Fri='white'
for dragon in DragonColor:
#列舉成員
print(dragon)#輸出 DragonColor.Mon
DragonColor.Tue
DragonColor.Wed
DragonColor.Thu
DragonColor.Fri
#列舉成員名稱
print(dragon.name)#輸出 Mon
Tue
Wed
Thu
Fri
# #列舉成員值
print(dragon.value)#輸出red
yellow
black
pink
white
唯一unique:
from enum import Enum,unique
@unique
class DragonColor(Enum):
Mon='red'
Tue='yellow'
Wed='black'
Thu='pink'
Fri='white'
5.5.4 類的三大特性(面向物件的三大特征)
5.5.4.1 封裝特性
類里面不光有屬性還有方法,這種將屬性通過方法直接在類內部操作的形式叫做封裝,這里的封裝是把屬性封裝在類內部,【根據職責將屬性和方法封裝到一個抽象的類中】
具體代碼如下:
class People(object):
def __init__(self,name):
self.__name = name
def setName(self,newname)
self.__name = newname
def getName(self):
return self.__name
p = People("xiaowang")
print(p.__name) #報錯
p.setName("xiaoxiaoming")
print(p.getName())繼承特性
5.5.4.2 繼承特性
◆繼承定義:
類的繼承是面向物件程式設計的一個重要思想,繼承時子類可以繼承父類的內容,包括成員變數和成員函式,在繼承中一個類被另外一個類繼承這個類稱之為父類或基類,則另外一個類則為子類或派生類,類從父類中繼承或派生,
【繼承實作代碼的重用(重復使用),相同的代碼不需要重復的撰寫,子類擁有父類的所有方法和屬性,子類繼承父類,可直接享受父類中已經封裝好的方法,不需要再次開發,子類中應該根據職責,封裝子類特有的屬性和方法】
◆繼承的傳遞性
C類從B類繼承,B類從A類繼承,則C類具有B類和A類所有屬性和方法,即子類擁有父類以及父類的父類中封裝的所有方法和屬性,
◆繼承的語法:
class 類名(父類名):
pass
具體代碼示例:
class Father(object): #Father繼承object類
def rich_man(self):
print '有錢'
class Son(Father):
def __init__(self):
Father.__init__(self) #繼承父類的建構式
def car(self):
print '喜歡跑車'
s = Son() #根據子類創建物件多型特性
◆單繼承
一個物件使用另一個物件的屬性和方法,被繼承的類也稱父類
(1)父類與子類的方法不一樣
(2)子類擁有與父類相同的方法,當子類擁有與父類相同的方法,通過子類實體呼叫該方法后,執行的是子類下的方法
(3)子類擁有與父類相同的方法和屬性
?基本語法:
class 類名(父類名):
pass
◆多繼承
多繼承就是一個子類繼承多個父類【子類擁有多個父類并且具有所有父類的屬性和方法】
? 如果不同的兩個父類出現了相同名稱的屬性或者方法,子類會繼承誰的屬性或者方法?
基本語法:
class 子類名(父類名1,父類名2)
pass
由上面實體可知如下
(1)python3中都是新式類:廣度優先,從父類中查詢對應的方法,查詢到第一個滿足的方法之后就直接回傳
object
|
A(object)
|
A_1(A) --> A_2(A)
|
Test(A_1, A_2)
(2)python2中的經典類:深度優先
A
|
A --> A_2(A)
|
A_1(A)
|
Test(A_1, A_2)
5.5.4.3 多型特性
◆多型是以繼承和重寫父類方法為前提,對所有子類實體化產生的物件呼叫相同的方法,執行產生不同的執行結果,【不同的子類物件呼叫相同的方法,產生不同的執行結果,增加代碼的靈活度】
例如同樣是人,但是當問起一個人的職業時會有不同的結果,可能是軟體測驗工程師,可能是HR
在Dog類中封裝方法game,普通的狗只是簡單的玩耍,定義xiaotianquan繼承Dog并重寫game方法;定義Person類,并封裝一個和狗子玩的方法(在方法內部,直接讓狗子物件呼叫game方法,)
【例】
#創建普通狗物件
class Dog(object):
def __init__(self,name):
self.name = name
def game(self):
print('%s蹦蹦跳跳的玩耍!!!'%self.name)
#創建XiaoTianQuan狗物件
class XiaoTianQuan(Dog):
def game(self):
print('%s在空中騰云駕霧!!!'%self.name)
class Person(object):
def __init__(self,name):
self.name=name
def game_with_dog(self,dog):
print('%s和%s快樂的玩耍'%(self.name,dog.name))
#Person類只需要讓狗物件呼叫game方法,game方法是在Dog父類中定義
dog.game()
#創建兩個狗物件
tom=XiaoTianQuan('飛天阿福')
laifu=Dog('來福')
#創建一個康康人物件
lily=Person('康康')
#在程式執行時,傳入不同的狗物件實參,就會產生不同的執行效果
lily.game_with_dog(tom)#輸出 康康和飛天阿福快樂的玩耍 飛天阿福在空中騰云駕霧!!!
# 康康呼叫和狗子玩的方法
lily.game_with_dog(laifu)#輸出 康康和來福快樂的玩耍 來福蹦蹦跳跳的玩耍!!!
◆一個物件的屬性和行為不是由他所繼承的父類決定的,而是由其本身包含的屬性和方法決定的,
class Animal(object):
def talk(self):
print('我是動物')
class Cat(Animal):
def talk(self):
print('喵喵')
class Dog(Animal):
def talk(self):
print('汪汪')
c = Cat()
c.talk()
◆Python中多型的特點
1、只關心物件的實體方法是否同名,不關心物件所屬的型別;
2、物件所屬的類之間,繼承關系可有可無;
3、多型的好處可以增加代碼的外部呼叫靈活度,讓代碼更加通用,兼容性比較強;
4、多型是呼叫方法的技巧,不會影響到類的內部設計,
◆【拓展】
Java中多型性的表現: 多型性,可以理解為一個事物的多種形態,同樣python中也支持多型,但是是有限的的支持多型性,主要是因為python中變數的使用不用宣告,所以不存在父類參考指向子類物件的多型體現,同時python不支持多載,在python中 多型的使用不如Java中那么明顯,所以python中刻意談到多型的意義不是特別大,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/502576.html
標籤:其他
上一篇:云上開發如何實作持續代碼提交?
下一篇:LeetCode - 三數之和
