一、函數(shù)
1、意義:函數(shù)是組織好的,可重復(fù)使用的,用來實現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段
2、格式:def ?函數(shù)名(參數(shù)),中間處理完數(shù)據(jù)后 return 結(jié)束函數(shù)并返回數(shù)據(jù),return可不寫,默認(rèn)return None。

3、參數(shù):
? * ? ?形參:定義?函數(shù)時的 參數(shù)變量
? * ? ?實參:調(diào)用?函數(shù)時,使用的參數(shù)變量
? * ? ?傳遞:在函數(shù)調(diào)用的過程中,把實參的引用 傳遞給 形參?,使用實參的值來執(zhí)行函數(shù)體的過程。
? * ? ?引用:在?Python?中,函數(shù)的?實參/返回值?都是是靠?引用?來傳遞來的 即:形參引用實參執(zhí)行函數(shù)計算,所得結(jié)果被調(diào)用函數(shù)的地方引用
? * ? ?使用分類:
????(1)位置實參:?按照參數(shù)位置,依次傳遞參數(shù)

????(2)關(guān)鍵字實參:?如果不想嚴(yán)格按照順序傳遞參數(shù),也可以按關(guān)鍵字傳遞。

????(3)屬性參數(shù):指定參數(shù)數(shù)據(jù)類型,Python中沒有聲明類型的語句,所以如果沒有指定參數(shù)類型,當(dāng)你剛看到這個函數(shù)的時候,你根本不知道我這個函數(shù)的作用是兩個整數(shù)相加還是兩個字符串拼接,(在pycharm里,Ctrl把鼠標(biāo)放函數(shù)名上會顯示參數(shù)類型,或者使用function_name.__annotations__查看)

?????(4)缺省參數(shù):定義函數(shù)時,可以給?某個參數(shù)?賦值一個默認(rèn)值,具有默認(rèn)值的參數(shù)就叫做?缺省參數(shù)
? ? ? ? ? ? *????缺省參數(shù)的定義位置:沒有多值參數(shù)的時候在末尾。有多值參數(shù)的時候在多值參數(shù)前,最好別和多值參數(shù)一起用,下講(很重要、很重要、很重要)
? ??????????*? ??調(diào)用函數(shù)時,如果沒有傳入?缺省參數(shù)?的值,則在函數(shù)內(nèi)部使用?參數(shù)默認(rèn)值,

? ??????????*?? ??將常見的值設(shè)置為參數(shù)的缺省值,從而?簡化函數(shù)的調(diào)用,比如:對一個數(shù)組排序,一般都是升序,這個時候就可以設(shè)缺省值,調(diào)用的時候不傳參數(shù)也會默認(rèn)升序,當(dāng)需要降序的時候,傳對應(yīng)的參數(shù)讓他降序處理

? ? ? ? ? ? *????調(diào)用帶有多個缺省參數(shù)的函數(shù):在?調(diào)用函數(shù)時,如果有?多個缺省參數(shù),需要指定參數(shù)名,這樣解釋器才能夠知道參數(shù)的對應(yīng)關(guān)系!

?????(4)多值參數(shù):當(dāng)函數(shù)需要處理的參數(shù)個數(shù)不確定時,可使用 多值參數(shù)。
? ? ? ? ? ?* ? ?位置:參數(shù)列表末尾!(很重要、很重要、很重要)
? ? ? ? ? ?*???? python 中有兩種多值參數(shù):
????????????????????接收 元組:參數(shù)名前加 一個 *
????????????????????接收 字典:參數(shù)名前加 兩個 *
? ? ? ? ? ? *????一般在給多值參數(shù)命名時,習(xí)慣使用以下兩個名字
? ? ? ? ? ? ? ????? *args — 存放 元組 參數(shù)
????????????????????**kwargs — 存放 字典 參數(shù),(kw 即 keyword,kwargs 即 鍵值對參數(shù))
? ? ? ? ? ? ?* ? ?先 *args,后 **kwargs,這個順序是死的,不能改

? ? ? ? ? ? * ? 拆包,就是實參傳遞的規(guī)則。
? ? ? ? ? ? ? ? (1)再以位置,從0開始一一傳遞給除*、**之外的形參,這個時候缺省參數(shù)也會傳給一個值,因為系統(tǒng)判斷不出來你到底是否想給缺省參數(shù)傳值,為了清晰邏輯,當(dāng)有多值參數(shù)的時候,缺省參數(shù)的缺省值無效? ? ??
? ? ? ? ? ? ? ? (2)剩下的實參再以屬性分類,以第一個字典實參為基準(zhǔn),之前的整成數(shù)組傳遞給?一個*形參,之后的整成字典傳遞給兩個*的形參

4、匿名函數(shù):
? ? *????格式:lambda x ,y : x * y ?(fun =?lambda 參數(shù) : 返回值)
? ? *????fun:代表這個函數(shù),因為等號=代表賦值
? ? *????lambda,定義匿名函數(shù)的關(guān)鍵字,相當(dāng)于函數(shù)的def.
? ? * ? ?x ,y:形參,用逗號(,)分隔。可以傳入多個參數(shù),規(guī)則參照上面的參數(shù)說明,注意的是多值參數(shù)與缺省參數(shù)的順序要求好像沒那么嚴(yán)格,可以隨意,但是一般用不到,因為一行里你寫不了多少東西,參數(shù)多了你也用不上
? ? * ? : x * y:匿名函數(shù)的返回值,可以是一個值x,也可以是x*y這種處理數(shù)據(jù)的表達(dá)式,相當(dāng)于一般函數(shù)里return的值,必須要有一個返回值用來返回,不支持復(fù)雜的諸如邏輯判斷語句,只能寫最簡單的語句,最多支持到寫3元運算
? ? * ? ?使用:
? ? ? ? (1)直接用:print((lambda x: x +6)(5)) # 11
? ? ? ? (2) 賦值給變量后調(diào)用:fun= lambda x: x +6 print(?fun(5) )?? #11

? ? ? ? (3)嵌套使用:內(nèi)嵌lambda表達(dá)式可以獲得上層lambda函數(shù)的變量

? ? ? ? (4)高階函數(shù)(參數(shù)為函數(shù)的函數(shù)):
? ? ? ? ? ? ? ? *????filter:過濾 ? ? ?filter ( 匿名函數(shù),數(shù)據(jù)源)

? ? ? ? ? ? ? ? *????max/mix:最大/最小

? ? ? ? ? ? ? ? * ? ?sort:排序

? ? ? ? ? ? ? ? * ? ?map:循環(huán)讓每個元素執(zhí)行函數(shù),將每個函數(shù)執(zhí)行的結(jié)果保存到新的map中

? ? ? ? ? ? ? ? * ? ?reduce:合并、疊加

5、變量作用域
? ? 1、變量的作用域決定了在哪一部分程序你可以訪問哪個特定的變量名稱
? ? 2、分類:
? ? ? ? * ? ?全局變量:定義在函數(shù)外的擁有全局作用域,全局變量可以在整個程序范圍內(nèi)訪問。
? ? ? ? * ? ?局部變量:定義在函數(shù)內(nèi)部的變量擁有一個局部作用域,局部變量只能在其被聲明的函數(shù)內(nèi)部訪問
? ? 3、更改作用域:
? ? ? ? * ? ?場景:1、在函數(shù)內(nèi)改變函數(shù)外的變量值時
? ? ? ? * ? ?全局 ?-->> ?局部:global 關(guān)鍵字

? ? ? ? *????nonlocal :適用于函數(shù)嵌套,nonlocal關(guān)鍵字修飾變量后標(biāo)識該變量是上一級函數(shù)中的局部變量,如果上一級函數(shù)中不存在該局部變量,nonlocal位置會發(fā)生錯誤(最上層的函數(shù)使用nonlocal修飾變量必定會報錯)。
二、模塊
1、定義:是一個 Python 文件,以 .py 結(jié)尾,包含了 Python 對象定義和Python語句。
2、引入:
? ? *????import + 模塊路徑:引入模塊,使用到的時候需要 ?模塊名.函數(shù)(..)
? ? *????from + ?模塊路徑? +?import ?* :引入整個模塊的所有內(nèi)容,使用的時候可以直接 函數(shù)名(...)
? ? *????from ?+ ?模塊路徑? + ?import ?+ ?要引用的函數(shù):引入這個模塊里的指定部分,使用的時候可以直接 函數(shù)名(...)
? ? *????from…import *語句與import區(qū)別在于:
? ??????????import?導(dǎo)入模塊,每次使用模塊中的函數(shù)都要是定是哪個模塊。
? ??????????from…import *?導(dǎo)入模塊,每次使用模塊中的函數(shù),直接使用函數(shù)就可以了;注因為已經(jīng)知道該函數(shù)是那個模塊中的了。
? ? * ? ?被引用的幾個模塊里有一個同名的函數(shù),當(dāng)這個函數(shù)唄調(diào)用時,最后調(diào)的那個模塊的,就執(zhí)行哪個,其余的會被覆蓋
3、搜索路徑:
????(1)、當(dāng)前目錄
????(2)、如果不在當(dāng)前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
????(3)、如果都找不到,Python會察看默認(rèn)路徑。UNIX下,默認(rèn)路徑一般為/usr/local/lib/python/。
4、if__name__=='__main__': ??當(dāng) .py 文件被直接運行時,if __name__ == '__main__' 之下的代碼塊將被運行; 當(dāng) .py 文件以模塊形式被導(dǎo)入時,if __name__ == '__main__'之下的代碼塊不被運行 ,作用,有時候模塊里的函數(shù),為了方便測試直接就調(diào)用了,如果忘了注釋的話,當(dāng)作為模塊引用了之后,他會執(zhí)行你的測試代碼,為了容錯,所以有了這個規(guī)則
三、迭代器
? ?1、迭代器 :所有能使用for循環(huán)的基本都可以視為迭代器,嚴(yán)格的說任意對象,只要定義了__next__方法,它就是一個迭代器。因此,python中的容器如列表、元組、字典、集合、字符串都可以被稱作迭代器。
? ? 2、迭代:迭代就是從迭代器中取元素的過程。類似于for循環(huán)中取值,這種遍歷過程就被稱作迭代。
? ? 3、使用:
? ? ? ?(1) 先調(diào)用容器(以字符串為例)的iter()函數(shù)
? ? ? ? (2)再使用?next()?內(nèi)置函數(shù)來調(diào)用?__next__()?方法
? ? ? ? (3)當(dāng)元素用盡時,__next__()?將引發(fā) StopIteration 異常
四、生成器
? ??在 Python 中,使用了 yield 的函數(shù)被稱為生成器(generator)
? ??跟普通函數(shù)不同的是,生成器是一個返回迭代器的函數(shù),只能用于迭代操作,更簡單點理解生成器就是一個迭代器。
????在調(diào)用生成器運行的過程中,每次遇到 yield 時函數(shù)會暫停并保存當(dāng)前所有的運行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當(dāng)前位置繼續(xù)運行。
????調(diào)用一個生成器函數(shù),返回的是一個迭代器對象。
注:
? ? 1、yield;可以當(dāng)成return,它會阻斷函數(shù),并返回?yield后的值
? ? 2、生成器函數(shù),返回的是一個迭代器對象。這個很重要,以yield為分隔點,可以理解為它把這個函數(shù)拆成了兩個函數(shù),并且弄成了一個函數(shù)組,以010101 的順序被調(diào)用,直到函數(shù)內(nèi)的條件不成立 報StopIteration異常 結(jié)束,
? ? 3、使用生成器時一定要 try...except StopIteration:?處理異常
五、閉包
1、定義:函數(shù)套函數(shù),比如函數(shù)1里有一個變量a,還有了一個函數(shù)2,并且函數(shù)2調(diào)用了變量a,當(dāng)每次調(diào)用函數(shù)1的時候,其實和其他的函數(shù)使用看不出什么區(qū)別,重點是,當(dāng)把函數(shù)1賦值給了一個變量b的時候,熱鬧來了,下面上個圖來捋一下:

? ? ? ? ? ? (1)當(dāng)func1函數(shù)賦值給b的時候,創(chuàng)建了一個實例,我們知道,變量賦值后除非刪除變量或者重新賦值,不然這個實例是不會被清理的,那么也就是說a這個變量也會一直存在
? ? ? ? ? ? (2)22行的第一次打印,對于這個實例來說就干了兩件事,1、是改變了變量a的值為1,2、是對外返回了a的值,實例沒銷毀,變量a也沒銷毀
? ? ? ? ? ? (3)23行的第二次打印,重復(fù)了22行的事,所以這個時候a=2,24行同理 a=3
? ? ? ? ? ? (4)25行重點來了,函數(shù)1被重新賦值給了c,這個時候?qū)τ谝粋€全新的實例來說,內(nèi)部的變量a=0,所有的疑惑都在于變量b和c是兩個不相干的東西,互不影響且無交集,這個想清楚就沒問題了,所以打印c會從1開始
? ? ? ? ?總結(jié):每次賦值都生成一個新的實例,內(nèi)部會初始化
2、返回值注意:
? ? * ? ?func1 返回的一般是func2,不然沒有使用閉包的必要
? ? * ? ?當(dāng)func1的參數(shù)時函數(shù)的時候 func2 返回的必須是這個函數(shù)的實例,不然這個函數(shù)根本不會執(zhí)行

六、裝飾器
1、定義:裝飾器本質(zhì)上就是一個python函數(shù),它可以讓其它函數(shù)在不需要做任何代碼改動的前提下增加額外的功能,裝飾器的返回值也是一個函數(shù)對象??梢院唵卫斫獬梢粋€三層或三層以上的嵌套函數(shù)的組合的應(yīng)用, 一個函數(shù)可以使用多個裝飾器
2、作用:為已經(jīng)存在的函數(shù)或者對象添加額外的功能,抽離出大量與函數(shù)功能本身無關(guān)的雷同的代碼并且可以重復(fù)使用。
3、場景:插入日志、性能測試、事務(wù)處理、緩存、權(quán)限校驗等場景
4、規(guī)范:
? ? * ? ?必須有一個函數(shù)的形參
? ? * ? ?在被裝飾函數(shù)上一行 ,以 @+裝飾器名 的形式調(diào)用
? ? * ? ?裝飾器的內(nèi)部函數(shù)必須返回一個被裝飾函數(shù)的實例
? ? * ? ?裝飾器內(nèi)部函數(shù)參數(shù)要不設(shè)置成?*args, **kwargs,要不與被裝飾函數(shù)的形參相同
4、分類:
? ? 以函數(shù)類型劃分:
? ? (1) ?單函數(shù)裝飾器:不管裝飾后的函數(shù)調(diào)用幾次,只在首次的時候裝飾器起作用

? ? (2)嵌套函數(shù)裝飾器:根據(jù)閉包規(guī)則,每次調(diào)用被裝飾函數(shù)都會觸發(fā)裝飾器的內(nèi)部函數(shù)

? ? 以參數(shù)劃分:
? ? ? ? ? ? 裝飾器的內(nèi)部函數(shù)的參數(shù)個數(shù):當(dāng)被裝飾函數(shù)有參數(shù)的時候,裝飾器內(nèi)部函數(shù)必須有相同的形參,否則報錯。解釋一下:調(diào)用一個使用了裝飾器的函數(shù)的時候,他的執(zhí)行順序是把被裝飾的這個函數(shù)傳遞到裝飾器里,裝飾器里干兩類事,一是它自己內(nèi)部定義的一些方法,二是執(zhí)行傳進(jìn)來的這個被裝飾的函數(shù)并返回它的實例,那么,當(dāng)被裝飾函數(shù)有參數(shù)的時候,怎么能讓裝飾器內(nèi)部函數(shù)拿到這些參數(shù),從而順利完成被裝飾函數(shù)的實例化,答案是:在裝飾器內(nèi)部函數(shù)參數(shù)部分設(shè)置和被裝飾函數(shù)一樣的形參, ?這樣,既可以順利實例化被裝飾函數(shù),也可以在內(nèi)部函數(shù)有需要的時候拿到外面?zhèn)鬟M(jìn)來的數(shù)據(jù) ?
? ? ? ? (1)無參裝飾器:裝飾器內(nèi)部函數(shù)無參的時候,被裝飾函數(shù)也不能有參數(shù),否則報錯

? ? ? ? (2)有參裝飾器:
? ? ? ? ? ? ? ? * ? ?你有啥,我有啥;被裝飾函數(shù)的參數(shù)和裝飾器內(nèi)部函數(shù)的參數(shù)一樣

? ? ? ? ? ? ? ? * ? ?不管你有啥,我都有:裝飾器內(nèi)部函數(shù)以數(shù)組和字典的方式接收傳遞被裝飾函數(shù)的參數(shù),重點是下圖35行創(chuàng)建實例時的參數(shù)名里的那幾個*號,竊以為是和內(nèi)部函數(shù)參數(shù)身份的轉(zhuǎn)變有關(guān)系,面對被裝飾函數(shù)傳過來的數(shù)據(jù),它是形參,創(chuàng)建實例引用它的時候,它是實參

? ? ? ? ? ? 裝飾器有無參數(shù):
? ? ? ? ? ? ? ? * ? ?裝飾器不帶參數(shù):上面所有的例子都是,沒啥可說的
? ? ? ? ? ? ? ? * ? ?裝飾器帶參數(shù):是個三層以上的嵌套函數(shù),最外層函數(shù)接收參數(shù),根據(jù)參數(shù)的不同,做不同的操作

? ? 以實現(xiàn)方式劃分:
? ? ? ? (1)、以函數(shù)方式實現(xiàn),上面的就是這種
? ? ? ? (2)、以類的方式實現(xiàn) ?,在類的 __call__ 方法下 寫,使用方式同上

? ? 5、使用:
? ? ? ? * ? ?注解使用:類似于java的注解,在函數(shù)上方 @+裝飾名
? ? ? ? * ? ?類似函數(shù)調(diào)用,把被裝飾函數(shù)當(dāng)做參數(shù),扔進(jìn)裝飾器里

? ? ? ? ? ? 注意:這種情況會出問題,怎么回事等我查查
