Python 學習 python的自學從幾個月前斷斷續續地進行,想好好利用這個寒假,好好地學一學。 回顧 已學習:基本操作、函數 已有C++的一定基礎,只要註意python中比較特殊的部分就行 進入正題 lambda表達式 1. 語法 lambda _args: _expression lambda ...
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.
類似C++中在初始化行構造父類class Child(Father): def __init__(self, sth): """初始化父類""" super().__init__(sth)
- 覆蓋父類的函數/方法:只要子類的函數名和父類有的函數重覆了就會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即可。