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