[学习总结] python语言学习总结 (三)
函數閉包
定義
延伸了作用域的函數(能訪問定義體之外定義的非全局變量
作用
代碼
print("Class方式:") class Averager:def __init__(self):self.series = []def __call__(self,new_val):self.series.append(new_val)return sum(self.series)/len(self.series) avg1 = Averager() print(avg1(3)) print(avg1(2))print("閉包方式:") def Avg_1():count = 0total = 0def Avg_2(val):nonlocal total,counttotal+=valcount+=1return total/countreturn Avg_2 avg = Avg_1() print(avg(9)) print(avg(10)) ''' 輸出 Class方式: 3.0 2.5 閉包方式: 9.0 9.5 '''理解
功能說明
這段代碼需要解決的是,定義一個average函數,我們每次傳進去一個值,都可以得到這個值和之前傳入值的平均值。比如第一次傳入1,均值就是1,第二次傳入2,均值就是1.5,以此類推。
類方式
第一種方式是通過構建一個類,這也是我們通常容易想到的方式,利用在類里面創建一個list,每次調用都將新值append進去,這是一種解決方法。
函數閉包方式
這里跟前面提到的作用域是有關的,函數閉包延伸了作用域,我們可以看到,我們的外層函數只是為了存儲兩個變量而已,沒有其他作用了。其實這時候應該有個疑惑,在調用Avg_1()之后,由于count和total是在Loval層,函數調用結束了應該銷毀了才是,但實際上并沒有,我們在Avg_2中通過nolocal關鍵字延長了兩個變量的生命周期,使得我們在每次調用的時候都能訪問都兩個變量,達到效果。
裝飾器
為什么會出現裝飾器這個東西
- 名稱管理
- 顯示調用
- 就近原則
- 充分復用
@語法糖
'@' 用做函數的修飾符,可以在模塊或者類的定義層內對函數進行修飾,出現在函數定義的前一行,不允許和函數定義在同一行。
什么是裝飾器
- 裝飾器是一個可調用的對象,以某種方式增強函數的功能
- 裝飾器是一個語法糖,在源碼中標記函數(此源碼指編譯后的源碼)
- 解釋器解析源碼的時候將被裝飾的函數作為第一個位置參數傳給裝飾器
- 裝飾器可能會直接處理被裝飾函數,然后返回它(一般僅修改屬性,不修改代碼)
- 裝飾器也可能用一個新的函數或可調用對象替換被裝飾函數(但核心功能一般不變)
- 裝飾器僅僅看著像閉包,其實功能的定位與閉包有重合也有很大區別
- 裝飾器模式的本質是元編程:在運行時改變程序行為
- 裝飾器的一個不可忽視的特性:在模塊加載時立即執行
- 裝飾器是可以堆疊的,自底向上逐個裝飾
- 裝飾器是可以帶參數的,但此時至少要寫兩個裝飾器
- 裝飾器的更加Pythonic的實現方式其實是在類中實現 call() 方法
代碼
def check_param(**kw):flag = kw.get('flag')def check_p(func):def decorate(*args):if flag:if not all([isinstance(arg,int) for arg in args]):raise TypeError("{} only accepts integers as argument".format(func.__name__))return func(*args)return decoratereturn check_p@check_param(flag=True) def my_sum(a,b):return a+bif __name__=='__main__':print(my_sum(1,2))print(my_sum(1,2.0))''' 輸出 3 Traceback (most recent call last):File "/home/xueaoru/文檔/pydemo/blog.py", line 18, in <module>print(my_sum(1,2.0))File "/home/xueaoru/文檔/pydemo/blog.py", line 7, in decorateraise TypeError("{} only accepts integers as argument".format(func.__name__)) TypeError: my_sum only accepts integers as argument'''解釋
上面的代碼是為了完成一個檢查my_sum函數的參數是否是整數的功能的裝飾器,同時增加了開關功能,我們將flag設置為true就是開啟檢查功能,如果不是整數,則直接報錯。
理解
裝飾器是對函數在不改變原有函數內部實現的情況下,對原有函數進行功能增強。而@語法糖是對原函數進行修飾的修飾符,當調用@語法糖進行修飾的時候,即使該函數并不調用,也會執行修飾語句,因為觸發了運行裝飾器。這時候該函數作為參數傳給修飾函數的外部函數,然后該函數作為引用賦值給內部函數的函數名,也就是說我們真正的操作是在內部函數中進行的,因此可以在內部函數中對原函數進行功能增強。其中,有參數的時候呢,內部函數也需要通過*和**拆包得到參數,原函數有返回值的時候呢,我們在調用完原函數的時候也應該給出返回值。而裝飾器本身帶參數的時候呢,可以在裝飾函數外再加一層接收參數的包裝得到參數。
OOP In Python
概念
一切都是對象
從語言設計層面理解Python中的數據類型:一切都是對象,都是從Object繼承過來的。Object由三部分組成:identity、type、value。
identity
理解
當Objects創建之后呢,identity也不會改變,直到被銷毀。我覺得跟c++里的地址差不多吧,當然也不能完全這么理解,也有不同的方。
要點
- 變量存儲的是創建的Object的identity
- 創建出來的不同Object有不同的identity
- 變量的id變了不是因為Object的identity變了,而是對應的Object變了
- 對于不可變對象而言,計算結果如果已經存在,可以直接返回相同的identity
type
要點
- 當Object創建后,其type不會改變
- type決定了一個Object可以支持那些運算,可能的值在哪些范圍
value
要點
- 有些Object的value可以改變:可變對象
- 有些Object的value不可以改變:不可變對象
每一個class在定義的時候如果沒有繼承的話,那么他繼承的就是Object這個超級class,而每一個自定義的class在python中都是一個type object。
@classmethod
理解
可以把類中的某個方法變成這個類的方法而不依賴于對象,也就是說,在對象沒有創建的時候,我們也可以調用這個類的方法執行一定的操作。這就有點像C++中的靜態成員函數。
代碼
class Student:teacher_name = "Omg"def __init__(self,name):self._name = name@classmethoddef Teacher(cls):print(cls.teacher_name)def Me(self):print(self._name) if __name__== '__main__':aa = Student("xue")aa.Teacher()aa.Me()Student.Teacher() ''' Omg xue Omg '''解釋
這段代碼是通過調用Teacher方法得到老師的名字,可以看出,我們就算不通過對象直接調用,也可以輸出老師的名字。classmethod就起這個作用。
@property
理解
本質上這是一個裝飾器,可以省去寫get、set函數的對外綁定。
property
函數原型為
property(fget=None, fset=None, fdel=None, doc=None)代碼
@property與下面的代碼效果是一樣的
class Teacher:def __init__(self,name,subject):self._name = nameself._subject = subjectdef setName(self,name):self._name = namedef getName(self):return self._namedef setSubject(self,subject):self._subject = subjectdef getSubject(self):return self._subjectdef show(self):print("name is:{} and subject is:{}".format(self._name,self._subject))name = property(getName,setName)subject = property(getSubject,setSubject) if __name__ == '__main__':t = Teacher("A","math")t.show()t.name = "B"t.subject = "English"t.show() ''' name is:A and subject is:math name is:B and subject is:English '''使用@property之后的更加優美的版本
class Teacher:def __init__(self,name,subject):self._name = nameself._subject = subject@propertydef name(self):return self._name@name.setterdef name(self,name):self._name = name@propertydef subject(self):return self._subject@subject.setterdef subject(self,subject):self._subject = subjectdef show(self):print("name is:{} and subject is:{}".format(self._name,self._subject)) if __name__ == '__main__':t = Teacher("A","math")t.show()t.name = "B"t.subject = "English"t.show()注意
這里@property必須在setter前面初始化,這個應該很容易理解,因為解釋器讀程序的時候是從上往下讀的。
Special method
要點
代碼
class A:def __init__(self):passdef __str__(self):return "I am str"def __len__(self):return 15def __bool__(self):return Falseif __name__ == '__main__':a = A()print(a,len(a),a==True)轉載于:https://www.cnblogs.com/aoru45/p/9937751.html
總結
以上是生活随笔為你收集整理的[学习总结] python语言学习总结 (三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用tushare进行对兴业银行股价的爬
- 下一篇: 程序10 VC编写批量重命名工具