Python 學習
python的自學從幾個月前斷斷續續地進行,想好好利用這個寒假,好好地學一學。
回顧
已學習:基本操作、函式
已有C++的一定基礎,只要注意python中比較特殊的部分就行
進入正題
lambda表示式
1. 語法
lambda _args: _expression
lambda函式是匿名的:所謂匿名函式,通俗地說就是沒有名字的函式。lambda函式沒有名字。
lambda函式有輸入和輸出:輸入是傳入到引數列表_args的值,輸出是根據表示式_expression計算得到的值。
lambda函式一般功能簡單:單行_expression決定了lambda函式不可能完成複雜的邏輯,只能完成非常簡單的功能。由於其實現的功能一目瞭然,甚至不需要專門的名字來說明。
2. 一些小例子
lambda x: x ** 2
lambda x, y: x * y
lambda *args: sum(args)
lambda **kwargs: 1
- 在變數名前加*表示可以傳入任意數量個引數
- 在變數名前有**表示用“關鍵字=值”的方式傳遞一個字典給函式
-
def func(**args): d = {} for key, value in args.items(): d[key] = value print(d) func(year=`2019`, month=`1`)
- {`year`: `2019`, `month`: `1`}
-
3. 使用方法
1. 直接將lambda函式賦值給一個變數,讓這個變數具有函式的功能,類似於C++中的仿函式(functor)
e.g. square = lambda x: x * x
2. 按照字典的值(value)進行排序,得到key的有序序列
e.g sorted(a_dict, key=lambda x:x[1])
從CSDN上看到的
例如,為了把標準庫time中的函式sleep的功能遮蔽(Mock),我們可以在程式初始化時呼叫:time.sleep=lambda x:None。這樣,在後續程式碼中呼叫time庫的sleep函式將不會執行原有的功能。例如,執行time.sleep(3)時,程式不會休眠3秒鐘,而是什麼都不做.
函式的返回值也可以是函式。例如return lambda x, y: x+y返回一個加法函式。這時,lambda函式實際上是定義在某個函式內部的函式,稱之為巢狀函式,或者內部函式。對應的,將包含巢狀函式的函式稱之為外部函式。內部函式能夠訪問外部函式的區域性變數,這個特性是閉包(Closure)程式設計的基礎,在這裡我們不展開。
將lambda函式作為引數傳遞給其他函式。
filter函式。此時lambda函式用於指定過濾列表元素的條件。例如filter(lambda x: x % 3 == 0, [1, 2, 3])指定將列表[1,2,3]中能夠被3整除的元素過濾出來,其結果是[3]。
sorted函式。此時lambda函式用於指定對列表中所有元素進行排序的準則。例如sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))將列表[1, 2, 3, 4, 5, 6, 7, 8, 9]按照元素與5距離從小到大進行排序,其結果是[5, 4, 6, 3, 7, 2, 8, 1, 9]。
map函式。此時lambda函式用於指定對列表中每一個元素的共同操作。例如map(lambda x: x+1, [1, 2,3])將列表[1, 2, 3]中的元素分別加1,其結果[2, 3, 4]。
reduce函式。此時lambda函式用於指定列表中兩兩相鄰元素的結合條件。例如reduce(lambda a, b: `{}, {}`.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])將列表 [1, 2, 3, 4, 5, 6, 7, 8, 9]中的元素從左往右兩兩以逗號分隔的字元的形式依次結合起來,其結果是`1, 2, 3, 4, 5, 6, 7, 8, 9`。
一些小東西
- 列表的分片: s[:], s[:-1], s[n:m]。分片區間[n, m),當n或m為負值的時候,實際值為len(s)+n。
- 列表的pop(): 不要和stack的pop搞起來了,列表pop是刪除最後一個元素!
- 列表的remove(value): 可以直接將列表中的value這個值刪掉
- .sort()與sorted(sth): s.sort()是永久排序,sorted排序一個物件,返回的有序的一個列表,不會對原始物件做改變
- .reverse(): 永久逆序列表
- 生成列表的小技巧: squares = [x ** 2 for x in range(11)],此時squares的內容是0~10的平方數(且有序)。這個很實用
- 複製列表:copy 和 deepcopy,涉及到python中變數儲存的方式,下文會談,這邊先提到一下。(自己思考思考)
- 字典刪除鍵-值對: 用del關鍵字。del d[`key`]
- 字典新增鍵-值對: 直接d[`new_key`] = new_value 即可
- 遍歷字典: for key, value in d.items():
函式
只記錄一些比較新的點
- 函式的引數傳遞:
- 有預設值的情況和C++一樣(順序,預設值的位置)
- 可以用關鍵字傳遞形參,e.g. fun(name=`abc`),此時不關乎順序
- 形參表接受任意個引數,在形參名前加*
e.g.
def square_sum(*args): res = sum([x ** 2 for x in args]) return res
這裡的args其實是一個元組(tuple)
- 使用任意數量的關鍵字實參,上面提到過
e.g.
def add_info(user_info, **new_info): for key, value in new_info.items(): user_info[key] = value
這裡的new_info接受到的只一個字典
-
函式的命名法則
這個看個人喜好吧,只要表達清楚,看得懂就行,我採用下劃線命名法
類
終於到了物件導向的東西了,看看和C++的差別有多少呢
- 編碼風格:
- python中的類名稱規定是首字母大寫的大駝峰法命名
- 例項名和模組名用下劃線命名法,類之間用兩個空行分開
- 在class Name() 的括號中,到底要不要加object呢?網上看了一下說python2最好加object,暫時我先不加了,遇到問題再說
- 成員函式:
- 建構函式
__init__
(self): - 所有成員函式的形參列表都要加上self,類似於c++類中的this指標,只不過python用的是顯式但不用真正傳遞,因此,每一個成員資料或者函式在類內使用的時候都要加上self.
- 建構函式
- 關於public和private:
好像在python的類中是沒有明確說明有這兩種以及protected情況的。經過我一番搜尋,發現三種屬性可以用下劃線來解決。- 沒有下劃線的變數,如self.public是public屬性
- 有一個下劃線的,如self._protected是protected屬性(只有子類可以訪問,且不能通過import匯入)
- 有兩個下劃線的,如self.__private是private屬性
- 繼承:
- 語法:在子類的括號中加上父類的名稱
- 特殊函式super():寫在子類的建構函式中
e.g.
class Child(Father): def __init__(self, sth): """初始化父類""" super().__init__(sth)
類似C++中在初始化行構造父類
- 覆蓋父類的函式/方法:只要子類的函式名和父類有的函式重複了就會override
- python的繼承順序,簡要提一下:python2是深度優先,python3是廣度優先,具體可以參考:Python類的繼承
- 其他:
暫時沒有學到什麼東西了,碰到了再深入下去。
Python特殊的引用變數
- 其實python中每個變數名所擁有的內容其實是一個引用(指標)指向的是一個靜態池中的常量
- 所以當變數給變數賦值的時候,給的值並不是他所對應的常量,而是將自己的指標的地址給了另一個變數,導致了這兩個變數同時共享這一個常量
- 如果改變一個變數中的值,即改變了這個常量的值,那麼另一個變數的值也隨之改變。
- 因此在列表賦值的時候,不要直接用=,而是用a = s[:]的方式,因為s[:]是s的一份拷貝,新的列表,這就是上面所提到的一種copy,這種方法等效於a = s.copy()
e.g.
>>> a = [1, 2, [3, 4]]
>>> b = a.copy()
>>> b[0] = 3
>>> b
[3, 2, [3, 4]]
>>> a
[1, 2, [3, 4]]
#a沒有受到影響,拷貝成功
- 但是,注意b這裡是二維的,如果改變了第二位的列表中的值,a會受到影響嗎。
e.g.
>>> b[2][0] = 123
>>> b
[3, 2, [123, 4]]
>>> a
[1, 2, [123, 4]]
#a受到影響了!
- 可以想象到,在copy的過程中是將a列表中每個元素的值重新拷貝了一份新的引用給b,但是,中間巢狀的列表[2, 3, 4](看做一個元素)的值其實是一個引用(這裡要好好想一下哦),把一個一樣的值(也就是地址一樣的指標)給了b,那麼其實b這個位置的元素和a這個位置的元素共享的是一個地址,會受影響。
- 為了解決這個問題,
import copy
,使用copy.deepcopy()
e.g.
>>> b = copy.deepcopy(a)
#此時b和a不會相互影響,自己做一下實驗吧
- 根據我自己的理解解釋一下(下次去查一下官方說明),deepcopy所做的事情其實是遞迴copy,層層深入copy
- 還有一件比較重要的事情:根據上述所說,operator =賦值的都是引用,因此函式在形實結合之後,函式體內改變形參同樣會改變實參,如果不想這樣,怎麼做上面寫了幾個方法。有點像c++中預設傳遞T&(引用)型別。
python中的多檔案
- 據我現在的理解,就是將函式,類寫在別的.py檔案,用的時候import即可。