函數在實際使用中有不少不同的小九九,我將從最基礎的函數內容,延伸出函數的高級用法。此文非科普片~~python
目前全部的文章思想格式都是:知識+情感。 知識:對於全部的知識點的描述。力求不含任何的自我感情色彩。 情感:用我本身的方式,解讀知識點。力求通俗易懂,完美透析知識。
首先介紹函數是什麼,接着走進函數,而且發現函數的高級使用方法,最後列出經常使用的Python的內置函數。linux
1.函數,在代碼執行的是不執行,只有在調用函數的時候纔會執行。閉包
2.函數使用關鍵字: def進行定義,看下面:併發
In [1]: def demo(): ...: print('I am a demo ...') ...: In [2]: demo() I am a demo ...
3.書寫函數的時候,默認返回值是:None。而且須要書寫函數的說明文檔。函數內部在必要的位置進行寫註釋,對應的執行內容說明。app
1.函數傳遞數據的參數
1)在函數括號中書寫的是形參
2)調用函數傳遞的數據,叫作實參函數
2.函數形參的分類
1)位置參數,經過書寫數據的前後位置進行數據的傳輸。看代碼~傳遞參數的順序大數據
2)默認參數,直接在函數中進行默認指定數據,函數調用的時候,能夠傳遞也能夠不傳數據。看下面,sex屬於默認參數。ui
3)關鍵字參數,在調用函數的時候,直接指定形參的名字進行傳輸數據。看下面,age屬於關鍵字傳參。設計
In [3]: def func(name, age, sex='male'): ...: print('My name is %s,I am %s years old, I am a %s.' %(name, age, sex)) ...: In [4]: func('rongming', age=18) My name is rongming,I am 18 years old, I am a male.
4)非固定參數
使用 args , * kwargs 表示
其中,*args 能夠傳遞任意非鍵值對數據,而且存儲爲元組形式。code
3.函數做用域
1)規則:只要是進行了代碼的縮進(一個tab鍵或者四個空格,大多數都是有做用域的產生。)
2)函數內部與函數外部,所包含的變量不在同一個做用域,變量的查找範圍是LEGB。
表示在函數內部調用變量,優先去本身當前區域(locals)找,接着去函數嵌套空間中(enclosing function)找,再接着去全局空間(globals)找,最後去內置模塊空間(builtins)找。
3)查看局部變量與全局變量方法:
局部變量 locals()
全局變量 globals()
4)函數內部使用外部的變量
使用, global,例如: global name # 在函數內部聲明全局變量name,不推薦
可使用nonlocal, 例如:nonlocal name,一樣也能夠,推薦
4.函數中的坑
注意:函數或者說Python中更改數據產生的坑均可以是不可變數據類型,因此須要從底層認清楚不可變數據類型的存儲方式,必定要記住不可變數據類型只是相對於不可變數據類型中元素的不可變。
注意:若是在函數內部使用函數外部的字典或者列表 這些可變數據類型,在函數中能夠修改函數外的內容,沒想到吧~~~
定義:接收函數爲參數,或者把函數做爲結果返回的函數是高階函數。
嵌套函數就是函數裏面還寫函數的樣子~
看一下示例:(func函數裏面寫inner函數)
def func(): a = 10 def inner(): print(a) return inner
匿名函數使用關鍵字: lambda。看下面的例子:
addfunc = lambda x: x*3
注意:因爲匿名函數能夠將函數簡寫爲一行,而且你們看着逼格高,因此在某些時候,應用仍是比較多的。
例子: map() 與匿名函數應用場景場景
s = map(lambda x: x+10, [i for i in range(10)]) for i in s: print(i) 10 11 12 13 14 15 16 17 18 19
1.遞歸函數: 遞歸表示在函數執行的時候,內部調用自身執行。
注意: 函數退出是否須要執行代碼,也就是函數在調用自身的以後還有沒有代碼執行,超過遞歸默認次數,會產生棧溢出。
2.知識點:
pycharm裏棧溢出報錯是:
Process finished with exit code -1073741571 (0xC00000FD)
** linux棧溢出報錯是:**
Segmentation fault (core dumped)
3.遞歸棧容量:
OS default sys.setrecursionlimit(100000) win 996 2512 linux 998 16361 linux默認遞歸棧容量是8M,能夠經過ulimit -s擴充。
注意:必定要注意閉包的定義是什麼!!!
1.閉包的產生條件,在嵌套函數中才會出現,閉包表示匿名函數,閉包的本質屬於函數做用域的延伸(不侷限於函數體內的做用域),只要在嵌套函數中內部函數能夠訪問自己以外的全局變量就稱爲閉包。
閉包中,內部函數訪問的外部變量叫作自由變量。
實現閉包的例子:
In [4]: def func(): ...: """閉包""" ...: numbers = [] ...: ...: def inner(num): ...: numbers.append(num) ...: return numbers ...: ...: return inner ...: In [5]: num = func() In [6]: num(10) Out[6]: [10] In [7]: num(11) Out[7]: [10, 11] In [8]: num(12) Out[8]: [10, 11, 12]
2.閉包的底層
閉包能夠實現對於自由變量的調用,關鍵點在於閉包函數存在一個Python的__ code 屬性(對代碼編譯後的函數的定義體)中,存在一個函數的 closure __的屬性,將自由變量進行綁定。
看下面的示例:
In [15]: num.__closure__ Out[15]: (<cell at 0x000001A723D50348: list object at 0x000001A7234789C8>,) In [16]: num.__closure__[1] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-16-56cdbd3f3ffc> in <module> ----> 1 num.__closure__[1] IndexError: tuple index out of range In [17]: num.__closure__[0].cell_contents # 取到的num.__closure__[0]屬於cell對象,存在cell_contents屬性 Out[17]: [10, 11, 12] In [18]: num.__code__.co_freevars # 函數體中的,綁定的自由變量 Out[18]: ('numbers',) In [19]: num.__code__.co_varnames # 函數體內部的本地變量 Out[19]: ('num',)
注意:裝飾器不要懵逼~~給我一塊兒透析它
1.使用@加上函數名字,而且放在另外一個函數上面的樣式就是說,搞了個裝飾器,別矇蔽,如今就已經認識裝飾器了~
2.裝飾器使用的是閉包的思想,既然是閉包的思想,那麼是否是會在被裝飾的函數的函數,返回一個對應函數內部的函數名(地址)。
重點:此時被裝飾的函數就再也不是你們肉眼看的函數了,而是被返回裝飾的函數內部函數,一旦調用,就先執行了裝飾器裏面的內容,在執行函數的執行內容。(仍是看代碼吧~)
3.時間裝飾器
In [26]: import time ...: import functools ...: ...: ...: def timer(func): ...: @functools.wraps(func) ...: def inner(*args, **kwargs): ...: start = time.time() ...: res = func(*args, **kwargs) ...: end = time.time() ...: print('This code used %s sec.' % (end - start)) ...: return res ...: return inner ...: ...: ...: ...: @timer ...: def func(num1, num2): ...: time.sleep(3) ...: return num1 + num2 ...: In [27]: func(10, 33) This code used 3.008526563644409 sec. Out[27]: 43
1.生成器,全部的生成器都是迭代器,generator,只須要將列表生成式變爲()便可,看下面
In [28]: s = [i for i in range(10)] In [29]: s Out[29]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] In [30]: b = (i for i in range(10)) In [31]: b Out[31]: <generator object <genexpr> at 0x000001A7223B0228>
2.生成器, 防止大數據生成,省空間,在作大數據生成的時候,能夠保證,用多少我產生多少,佔用多大的空間。產生的用完了就會報錯StopIteration。
In [41]: b = (i for i in range(10)) In [42]: next(b) Out[42]: 0 In [43]: next(b) Out[43]: 1 In [44]: for i in b: ...: print(i) ...: 2 3 4 5 6 7 8 9 In [45]: next(b) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-45-adb3e17b0219> in <module> ----> 1 next(b) StopIteration:
1.函數生成器,保證了函數能夠,在執行一半的時候,乾點其餘的事,而且能夠將乾的事返回到函數中,這也是協程的思想。全部的生成器都是迭代器。
2.實現函數生成器,只須要在函數內部添加yield便可。而且知識函數外部傳遞參數到函數內部,在初始化生成器的時候,須要使用__next__ 調用生成器,此時發送None到yield啓動生成器,就可使用next()進行調用了!其中,send() 表示調用生成器,併發送數據。
3看代碼:
In [46]: def gen(a): ...: while a < 10: ...: yield a ...: a += 1 ...: In [47]: gen(5) Out[47]: <generator object gen at 0x000001A723309228> In [48]: b = gen(5) In [49]: next(b) Out[49]: 5 In [50]: next(b) Out[50]: 6 In [51]: for i in b: ...: print(i) ...: 7 8 9
1.迭代器的構建使用:iter() ,能夠將可迭代對象變爲迭代器。
2.可使用isinstance()判斷是否是iterator,可使用next()調用,for循環調用。
3.例子:
In [52]: s = iter(i for i in range(10)) In [53]: s Out[53]: <generator object <genexpr> at 0x000001A7226116D8> In [54]: next(s) Out[54]: 0 In [55]: next(s) Out[55]: 1 In [56]: for i in s: ...: print(i) ...: 2 3 4 5 6 7 8 9 In [57]: next(s) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-57-61c30b5fe1d5> in <module> ----> 1 next(s) StopIteration:
Python 的內置函數不少,可是仍是能夠排列一個順序的,因此下面我將我本身經常使用的函數進行一個順序排列:
print() id() enumerate() str() 字符的集合 list() 元素的集合 bytes() map() sum() isinstance() next() abs() max() min() bool() all() iterable is bool() any() iterable is bool() bytearray() complex() divmod() eval() 字符串數據類型轉換成爲Python的數據類型 exec() 執行字符串 exit() filter() 符合條件的進行過濾 zip()
**Python的函數設計不少內容,實現功能要麼是函數,要麼是對象,因此有一些底層的內容,須要多加 挖掘,好比閉包的 __ code __,還有個自由變量等等。**
感慨:路還很長,本身最須要的是時間與經歷,加上一個不錯的理解能力~~