Python小知识 | 这些技能你不会?(终章)
零、寫在前面
寫完今天這一篇,Python小知識(shí)這塊就完了,一共四篇,也就是我過(guò)了一遍《零壓力學(xué)Python》后記錄下來(lái)的一些重要的點(diǎn),希望對(duì)初學(xué)者或者復(fù)習(xí)Python基礎(chǔ)的讀者有所幫助,再多的話我就不說(shuō)了,一切都在知識(shí)里面,加油。
一、面相對(duì)象三大特性
(1)封裝
封裝,即隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)接口,控制在程序中屬性的讀和修改的訪問(wèn)級(jí)別。
封裝在平時(shí)用的比較多,在編寫一個(gè)大項(xiàng)目的時(shí)候,我們會(huì)自覺(jué)地根據(jù)功能分類,這里類就是一種封裝,再細(xì)點(diǎn),類里的函數(shù)也是封裝,當(dāng)我們使用的時(shí)候,只用類名,函數(shù)名,而不接觸具體的類體和函數(shù)體,這樣的好處是顯而易見(jiàn)的,對(duì)自己,項(xiàng)目代碼更加易讀,可維護(hù)性更高,同時(shí)不怕功能代碼被串改,對(duì)別人,合作伙伴不需要知道底層實(shí)現(xiàn)的,更容易理解代碼含義(函數(shù),方法取名時(shí)自己就要注意了)。
(2)繼承
簡(jiǎn)單的說(shuō),繼承就是在一個(gè)現(xiàn)有類型的基礎(chǔ)上,通過(guò)增加新的方法或者重定義已有方法(下面會(huì)講到,這種方式叫重寫)的方式,產(chǎn)生一個(gè)新的類型。繼承是面向?qū)ο蟮娜齻€(gè)基本特征--封裝、繼承、多態(tài)的其中之一,我們?cè)谑褂肞ython編寫的每一個(gè)類都是在繼承,同JAVA語(yǔ)言中,java.lang.Object類是所有類最根本的基類(或者叫父類、超類),如果我們新定義的一個(gè)類沒(méi)有明確地指定繼承自哪個(gè)基類,那么Python就會(huì)默認(rèn)為它是繼承自O(shè)bject類的。
'''
data?:?2018.12.08
author?:?老表
goal?:?繼承簡(jiǎn)單例子
'''
class?allStr():
????'''?父類?'''
????all_words?=?"歡迎關(guān)注簡(jiǎn)說(shuō)Python!"
????other_words?=?"人生苦短,我選Python!"
????def?all_print(self):
????????'''?打印其他的話?'''
????????print(self.other_words)??#?調(diào)用自己的類變量
class?myStr(allStr):
????'''?子類?'''
????def?my_print(self):
????????'''?打印我的話?'''
????????print(allStr.all_words)??#?調(diào)用父類變量
#?初始化類對(duì)象
my_str?=?myStr()
#?調(diào)用類方法
my_str.my_print()
#?調(diào)用父類的方法
my_str.all_print()
#?企圖外部直接修改父類變量
my_str.all_words?=?"你好,我是老表,歡迎置頂公眾號(hào):簡(jiǎn)說(shuō)Python!"
#?調(diào)用類方法
my_str.my_print()
'''
result?:?
????歡迎關(guān)注簡(jiǎn)說(shuō)Python!
????人生苦短,我選Python!
????歡迎關(guān)注簡(jiǎn)說(shuō)Python!
'''
看上面的結(jié)果我們可以看出,我們不能直接在外部修改父類變量,在第三篇中有介紹,怎么修改類變量,也就是__init__方法的使用。
(3)多態(tài)
多態(tài)是指一個(gè)程序中同名的不同方法共存的情況。這些方法同名的原因是它們的終于功能和目的都同樣,可是因?yàn)樵谕戤呁还δ軙r(shí),可能遇到不同的詳細(xì)情況。所以須要定義含不同的詳細(xì)內(nèi)容的方法,來(lái)代表多種詳細(xì)實(shí)現(xiàn)形式。
多態(tài)包括:重載和重寫
重載
在一個(gè)類中定義了多個(gè)同名的方法,它們或有不同的參數(shù)個(gè)數(shù)或有不同的參數(shù)類型,則稱為方法的重載(Overloading)
重寫
在子類中定義某方法與其父類有同樣的名稱和參數(shù)和返回值,我們說(shuō)該方法被重寫 (Overriding)。
兩者易混淆,牢記區(qū)別:有繼承關(guān)系的是重寫,沒(méi)有的是重載。
"""
author?:?老表
data?:?2018.12.09
goal?:?多態(tài)實(shí)例
"""
class?AllStr:
????"""?父類?"""
????all_words?=?"你好,簡(jiǎn)說(shuō)Python!"
????my_words?=?"歡迎關(guān)注:簡(jiǎn)說(shuō)Python!"
????def?print_str(self):
????????print(self.all_words)
class?MyStr(AllStr):
????"""?子類?"""
????def?print_str(self):
????????"""?重寫父類的方法?"""
????????print(self.my_words)
????def?print_me(self):
????????"""?屬于自己的方法?"""
????????print("人生苦短,快學(xué)Python!")
????def?print_me(self,?your_words):
????????"""?重載自己類里的方法?"""
????????print(your_words)
#?初始化一個(gè)對(duì)象
my_str?=?MyStr()
#?調(diào)用重寫父類的方法
my_str.print_str()
#?調(diào)用自己特有的方法
#?my_str.print_me()?重載后,之前的方法不可調(diào)用
#?調(diào)用子類自己重載的方法
your_words?=?"我置頂了?簡(jiǎn)說(shuō)Python!"
my_str.print_me(your_words)
'''
result?:?
????歡迎關(guān)注:簡(jiǎn)說(shuō)Python!
????我置頂了?簡(jiǎn)說(shuō)Python!
'''
需要注意的是,在Python里面重載是不被推崇的,或者說(shuō)沒(méi)有,為什么呢?因?yàn)閷?duì)于Python這么優(yōu)雅的語(yǔ)言來(lái)說(shuō),重載是沒(méi)必要的,從重載的定義來(lái)看,在一個(gè)類中定義了多個(gè)同名的方法,它們或有不同的參數(shù)個(gè)數(shù)或有不同的參數(shù)類型,Python本身就不限制變量的數(shù)據(jù)類型,這是一點(diǎn),如果傳人變量個(gè)數(shù)不確定,還可以用*args,傳遞多個(gè)變量,想多少個(gè)就多少個(gè),這是其二,最后,如果兩個(gè)函數(shù)的功能確實(shí)有很大的不同,那么就沒(méi)必要硬取兩個(gè)相同的函數(shù)名了,直接取不同的函數(shù)名加以區(qū)分其實(shí)是更好的。
二、生命游戲
介紹
生命游戲是英國(guó)數(shù)學(xué)家約翰·何頓·康威在1970年發(fā)明的細(xì)胞自動(dòng)機(jī)。它包括一個(gè)二維矩形世界,這個(gè)世界中的每個(gè)方格居住著一個(gè)活著的或死了的細(xì)胞。一個(gè)細(xì)胞在下一個(gè)時(shí)刻生死取決于相鄰八個(gè)方格中活著的或死了的細(xì)胞的數(shù)量。如果相鄰方格活著的細(xì)胞數(shù)量過(guò)多,這個(gè)細(xì)胞會(huì)因?yàn)橘Y源匱乏而在下一個(gè)時(shí)刻死去;相反,如果周圍活細(xì)胞過(guò)少,這個(gè)細(xì)胞會(huì)因太孤單而死去。
基本規(guī)律
對(duì)于網(wǎng)格中的每個(gè)位置,計(jì)算有多少個(gè)鄰接位置中有活細(xì)胞,包括對(duì)角鄰接位置,因此一個(gè)方塊的周圍最多有八個(gè)活細(xì)胞(數(shù)值為1的方塊),最少為零,規(guī)則就是,如果這個(gè)方塊周圍的活細(xì)胞數(shù)等于三,就繁殖,也就是值變?yōu)?,如果這個(gè)方塊周圍的活細(xì)胞數(shù)少于兩個(gè)或者大雨三個(gè),則該方塊中細(xì)胞死亡,值變?yōu)?。
(1)Matrix2D類代碼實(shí)現(xiàn)
新建一個(gè)matrix2d.py文件,把下面代碼封裝到里面,一個(gè)專門用于處理二維數(shù)組的類。
"""
二維矩陣類
"""
class?Matrix2D:
????"""?通用的二維矩陣類?"""
????def?__init__(self,?rows,?cols):
????????"""?初始化矩陣row行,col列?"""
????????self.grid?=?[[0]*cols?for?_?in?range(rows)]
????????self.rows?=?rows
????????self.cols?=?cols
????def?get_cell(self,?r,?c):
????????"""?獲取單元格(r,c)的值?"""
????????return?self.grid[r][c]
????def?set_cell(self,?n,?**args):
????????"""?設(shè)置某個(gè)位置的值?"""
????????for?r,?c?in?args:
????????????self.grid[r][c]?=?n
????def?inc_cells(self,?**args):
????????"""?將任意的單元格?+1?"""
????????for?r,?c?in?args:
????????????self.grid[r][c]?+=?1
????def?set_all_cells(self,?n=0):
????????"""?將所有單元格值都設(shè)置為?n?"""
????????for?i?in?range(self.rows):
????????????for?j?in?range(self.cols):
????????????????self.grid[i][j]?=?n
(2)主函數(shù)
"""
生命游戲
"""
from?lifemat?import?Matrix2D
rows?=?5
cols?=?5
#?存儲(chǔ)圖符號(hào)的二維數(shù)組
life_mat?=?Matrix2D(rows,?cols)
#?存儲(chǔ)具體數(shù)據(jù)的二維數(shù)組
nc_mat?=?Matrix2D(rows,?cols)
#?初始化
life_mat.set_cells(1,?(1,?3),?(2,?1),?(2,?3),?(3,?2),?(3,?3))
#?創(chuàng)建邊界字符串
border_str?=?'?_?'?*?cols
def?get_mat_str(a_mat):
????"""?處理打印字符串?"""
????disp_str?=?''
????for?i?in?range(rows):
????????lst?=?[get_chr(a_mat,?i,?j)?for?j?in?range(cols)]
????????disp_str?+=?''.join(lst)?+?'\n'
????return?disp_str
def?get_chr(a_mat,?r,?c):
????"""?設(shè)置圖符號(hào)?"""
????return?'?1?'?if?a_mat.get_cell(r,?c)?>?0?else?'?0?'
def?do_generation():
????"""?打印當(dāng)前狀態(tài)并生成下個(gè)狀態(tài)?"""
????#?打印當(dāng)前生命矩陣狀態(tài)
????print(border_str?+?'\n'?+?get_mat_str(life_mat))
????#?把數(shù)據(jù)全部置0
????nc_mat.set_all_cells(0)
????#?根據(jù)圖符號(hào)矩陣life_mat來(lái)給nc_mat賦值
????for?i?in?range(rows):
????????for?j?in?range(cols):
????????????if?life_mat.get_cell(i,?j):
????????????????#?環(huán)繞圖像,使有限的二維數(shù)組變成沒(méi)有邊界的生命游戲
????????????????im?=?(i?-?1)?%?rows
????????????????ip?=?(i?+?1)?%?rows???#?當(dāng)前行號(hào)-/+?1
????????????????jm?=?(j?-?1)?%?cols
????????????????jp?=?(j?+?1)?%?cols???#?當(dāng)前列號(hào)-/+?1
????????????????#?設(shè)置數(shù)據(jù)量為?1?,表示有活細(xì)胞
????????????????nc_mat.inc_cells((im,?jm),?(im,?j),?(im,?jp),?(i,?jm),
?????????????????????????????????(i,?jp),?(ip,?jm),?(ip,?j),?(ip,?jp))
????#?根據(jù)鄰居數(shù)量矩陣按規(guī)則生成下一代
????for?i?in?range(rows):
????????for?j?in?range(cols):
????????????n?=?nc_mat.get_cell(i,?j)
????????????if?n?<?2?or?n?>?3:??????#?死亡現(xiàn)象
????????????????life_mat.set_cells(0,?(i,?j))
????????????elif?n?==?3:????????????#?繁殖現(xiàn)象
????????????????life_mat.set_cells(1,?(i,?j))
import?time
n?=?100
for?i?in?range(n):
????#?循環(huán)調(diào)用迭代
????do_generation()
????#?設(shè)置時(shí)間間隔
????time.sleep(1)
運(yùn)行效果
生命游戲運(yùn)行效果
錄了20s有興趣可以慢慢看~
建議自己先把邏輯思路理清,然后把代碼復(fù)現(xiàn)一遍,肯定有很大收獲哦~
《零壓力學(xué)Python》里說(shuō),學(xué)習(xí)新編程語(yǔ)言的時(shí)候,如果能使用它編寫出生命游戲,就說(shuō)明掌握了這門語(yǔ)言,編完后,我覺(jué)得是有很大道理的,不說(shuō)所有,能弄懂這個(gè)程序,至少可以說(shuō)明你的基礎(chǔ)過(guò)關(guān)了。
三、裝飾器
簡(jiǎn)單說(shuō)明是什么有什么用
簡(jiǎn)單的稱為裝飾其他函數(shù)的函數(shù)。
我先說(shuō)一下我的裝飾器的理解,然后再上一些例子。
裝飾器就是一個(gè)函數(shù),和一般函數(shù)一樣,裝飾器可以有返回值,參數(shù),代碼段,這個(gè)函數(shù)里面還包含了一個(gè)或多個(gè)函數(shù),對(duì),函數(shù)的嵌套,同樣里面的函數(shù)和一般函數(shù)也是一樣的,可以擁有一切普通函數(shù)該擁有的,簡(jiǎn)單來(lái)說(shuō),裝飾器就是把函數(shù)當(dāng)做普通變量來(lái)用,哪大家會(huì)好奇,裝飾器到底有什么用呢?
書上是這樣說(shuō)的”裝飾器給函數(shù)名重新賦值,使其指向原始函數(shù)的包裝板,包裝板不僅具備原始函數(shù)的所有功能,還添加了新功能“,這樣一理解,可以這樣轉(zhuǎn)化,裝飾器就是用來(lái)豐富函數(shù)功能的,那是嘛時(shí)候會(huì)起作用呢?
調(diào)試的時(shí)候,特別是對(duì)于大程序的調(diào)試,我不可能在一個(gè)模塊里幾百個(gè)函數(shù)一個(gè)個(gè)調(diào)試,這個(gè)時(shí)候來(lái)個(gè)裝飾器就很好了,或者說(shuō)我想驗(yàn)證某個(gè)東西,但不希望在原始函數(shù)添加,這個(gè)時(shí)候裝飾器就是一把利器了,下面讓我們隨這幾個(gè)例子來(lái)更好的學(xué)習(xí)裝飾器吧。
實(shí)例學(xué)習(xí)
1.最簡(jiǎn)單的例子
def?my_decorator(f):
????"""?裝飾器,將一個(gè)函數(shù)作為參數(shù)傳遞進(jìn)來(lái),進(jìn)行包裝,然后返回?"""
????def?wrapper():
????????print("I?am?doing?extra?stuff.")
????????f()
????????print("Doing?more?extra?stuff.")
????return?wrapper
def?hello():
????print("簡(jiǎn)說(shuō)Python 你好!")
new_hello?=?my_decorator(hello)
new_hello()
'''
result:
????I?am?doing?extra?stuff.
????簡(jiǎn)說(shuō)Python 你好!
????Doing?more?extra?stuff.
'''
2.中等簡(jiǎn)單
def?my_decorator(f):
????"""?裝飾器,將一個(gè)函數(shù)作為參數(shù)傳遞進(jìn)來(lái),進(jìn)行包裝,然后返回?"""
????def?wrapper():
????????print("I?am?doing?extra?stuff.")
????????f()
????????print("Doing?more?extra?stuff.")
????return?wrapper
'''
說(shuō)明一下:新語(yǔ)法,@+裝飾器的名稱,相當(dāng)于
def?hello():
????print("Hi,簡(jiǎn)說(shuō)Python!")
hello?=?my_decorator(hello)
'''
def?hello():
????print("Hi,簡(jiǎn)說(shuō)Python!")
hello()
'''
result:
????I?am?doing?extra?stuff.
????Hi,簡(jiǎn)說(shuō)Python!
????Doing?more?extra?stuff.
'''
3.復(fù)雜案例
from?time?import?time
def?diagnostics(f):
????def?wrapper(*args,?**kwargs):
????????"""?這個(gè)包裝函數(shù)帶參數(shù),
????????*args處理多個(gè)參數(shù),
????????**kwargs可以處理具名參數(shù)?"""
????????print("Executed",?f.__name__,?"at",?time())
????????value?=?f(*args,?**kwargs)
????????print("Exited",?f.__name__,?"at",?time())
????????print("Arguments:",args)
????????print("Value?returned:",?value,?"\n")
????????return?value
????return?wrapper
def?print_nums():
????"""?不帶參數(shù),沒(méi)有返回值?"""
????for?i?in?range(4):
????????print(i,?end="\t")
def?add_nums(a,?b):
????"""?帶參數(shù),有返回值?"""
????return?a+b
#?調(diào)用經(jīng)過(guò)裝飾器裝飾過(guò)的函數(shù)
print_nums()
print("-"*50)
add_nums(2,?3)
print("-"*50)
'''
result:
????Executed?print_nums?at?1544353643.8159559
????0???1???2???3???Exited?print_nums?at?1544353643.8159559
????Arguments:?()
????Value?returned:?None?
????--------------------------------------------------
????Executed?add_nums?at?1544353643.8159559
????Exited?add_nums?at?1544353643.8159559
????Arguments:?(2,?3)
????Value?returned:?5?
????--------------------------------------------------
'''
以上就是裝飾器的基本講解了,細(xì)細(xì)品讀,理清其中思緒,就能很好的理解和掌握了,希望對(duì)大家有所幫助。
靈活應(yīng)用這些基本操作,讓你的工作學(xué)習(xí)事半功倍。
推薦閱讀:(點(diǎn)擊標(biāo)題即可跳轉(zhuǎn))
總結(jié)
以上是生活随笔為你收集整理的Python小知识 | 这些技能你不会?(终章)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 趣图:如何假装自己是一个IT人?
- 下一篇: DigSci科学数据挖掘大赛:如何在3天