Python入門到逆襲7(進階篇1)
技術標籤:python入門到逆襲pythonlinuxredismysqlhttp
1. 函式
函式是組織好的,可重複使用的,用來實現單一,或相關聯功能的程式碼段,簡單來講,函式就是一段可重複執行的程式碼邏輯。
1.1函式示例
def test_func():
'''
這是一個測試函式
:return:
'''
print('這是一個測試函式')
return
解釋 :
def 函式定義的關鍵詞,函式必須以為def開頭來定義。
test_func 函式名,可自行定義,一般約定為(簡短、見名知意)
() 括號中用於定義引數,沒有引數的時候,則為空
‘’’‘’’函式的描述(好的函式先描述函式的功能,然後每個引數的格式和代表的意義和返回值)
接下來就是函式功能邏輯,自行編寫對應的程式碼實現
return使用者返回函式執行後返回的引數,沒有返回值可以不帶引數。
1.2函式呼叫
函式呼叫處處見,低頭不見抬頭見。例如我們在之前基礎篇中使用的系統庫函式,print、os.system等函式,都是函式的呼叫,現在的區別只在於我們呼叫的是我們自己實現的函式,呼叫方法還是一樣的。
下面,我們自定義一個函式和呼叫這個函式:
def save_cur_time(): ''' 儲存當前時間 :return: ''' localtime = time.localtime() str_time = time.strftime("%Y-%m-%d %H:%M:%S", localtime) fp = open('cur_time.txt', 'a+') fp.write(str_time) fp.write('\r\n') fp.close() def main(): ''' 主函式 :return: ''' save_cur_time() if __name__ == '__main__': main()
解釋:
main() 這裡是第一個函式呼叫,跳轉到main函式中執行程式碼
save_cur_time()是第二個函式呼叫,跳轉到save_cur_time函式中執行程式碼邏輯,儲存當前的時間到文字中。
執行結果:
1.3函式引數
- 不可變型別引數
在 python 中,strings, tuples, 和 numbers 是不可更改的物件。
即使在函式中臨時改變了引數的值,在函式執行結束後,引數的值還是原來的值。
例如:
def immutable_param(param): ''' 不可變型別引數函式 :param param: 引數值 (int) :return: ''' print('immutable_param param傳入值為 : {}'.format(param)) param = 10 print('immutable_param param修改後的值為 : {}'.format(param)) param = 1 immutable_param(param) print('函式結束後,param的值為: {}'.format(param))
結果:
immutable_param param傳入值為 : 1
immutable_param param修改後的值為 : 10
函式結束後,param的值為: 1
- 可變型別引數
在 python 中,list,dict 等則是可以修改的物件,如果在函式中臨時改變了引數的值,在函式執行結束後,引數的值就被永久的改變了。
例如:
def mutable_param(param):
'''
可變型別引數函式
:param param: 引數值 (dict)
:return:
'''
print('mutable_param param傳入值為 : {}'.format(param))
del param['1key']
param['10key'] = '10value'
print('mutable_param param修改後的值為 : {}'.format(param))
param = {'1key': '1value', '2key': '2value'}
mutable_param(param)
print('函式結束後,param的值為: {}'.format(param))
結果:
mutable_param param傳入值為 : {'1key': '1value', '2key': '2value'}
mutable_param param修改後的值為 : {'2key': '2value', '10key': '10value'}
函式結束後,param的值為: {'2key': '2value', '10key': '10value'}
- 預設引數
預設引數將會在函式的引數中設定一個預設值,當呼叫函式並且沒有傳遞該引數的時候,則會預設給該引數設定預設值,並在函式的範圍內生效。
例如:
def default_param(param1, param2 = 10):
'''
預設引數函式
:param param1: 引數1
:param param2: 預設引數,預設值為10
:return:
'''
print('default_param param1:{} param2:{}'.format(param1, param2))
default_param(1, 2)
default_param(1)
結果:
default_param param1:1 param2:2
default_param param1:1 param2:10
- 不定長引數
不定長引數函式,在我們一開始的時候就遇到了,例如神奇的main,再例如,神奇的print函式,例如print後面可以有一個引數,兩個引數.....N個引數,這裡我們就類似實現一個看一下,就容易理解了。
例如:
def variable_param(param1, *kwarg):
'''
可變引數函式
:param param1: 引數1
:param kwarg: 可變引數
:return:
'''
print('variable_param param1:{}'.format(param1))
for var in kwarg:
print('variable_param kwarg:{}'.format(var))
variable_param(10, 20, 30)
variable_param(10, 20, 30, 40, 50)
結果:
variable_param param1:10
variable_param kwarg:20
variable_param kwarg:30
variable_param param1:10
variable_param kwarg:20
variable_param kwarg:30
variable_param kwarg:40
variable_param kwarg:50
- 引數題外話 : (一般專案團隊都會做的一些約束)
- 引數預設不超過5個(超過5個會進行壓棧)
- 所有外部輸入引數,都需要做引數型別、有效值校驗
2.裝飾器
裝飾器,理解起來,有點費力, 需要層層深入,如果看完之後沒看懂,那就,在看一遍,還是不懂,多動手練習幾次,其義自見。
2.1萬物皆物件
物件這個概念,是變相物件程式語言中的概念,如果對這個概念不太熟悉,可以先看下一章”類”這一塊。
在程式語言中,除了int、string、dict等這項變數申明出來的是物件外,函式也是一個物件,函式名對應的就是一個函式地址。
例如:
def func_obj():
'''
函式物件測試函式
:return:
'''
print('這是一個函式')
print('func_obj函式物件: {}'.format(func_obj))
結果:
func_obj函式物件: <function func_obj at 0x7f9b6143f578>
解釋:
func_obj函式本身也是一個物件,儲存在記憶體中的地址為0x7f9b6143f578。
接上面示例:
func_obj()
func_test = func_obj
func_test()
結果:
這是一個函式
這是一個函式
解釋:
func_obj():正常的函式呼叫
func_test = func_obj: 將函式地址複製給func_test,這個和C裡面的函式指標是一樣的
func_test(): 執行函式func_obj
參考程式碼 :
https://github.com/minlixia/python(advanced/01_func.py)
2.裝飾器
裝飾器,理解起來,有點費力, 需要層層深入,如果看完之後沒看懂,那就,在看一遍,還是不懂,多動手練習幾次,其義自見。
可能下面前幾個章節關聯性並不是那麼強,可以單獨來理解,但是每個小章節優勢必須要了解的,因為最後完整的理解裝飾器的時候,需要這些小章節知識的結合彙總理解。
2.1萬物皆物件
物件這個概念,是變相物件程式語言中的概念,如果對這個概念不太熟悉,可以先看下一章”類”這一塊。
在程式語言中,除了int、string、dict等這項變數申明出來的是物件外,函式也是一個物件,函式名對應的就是一個函式地址。
例如:
def func_obj():
'''
函式物件測試函式
:return:
'''
print('這是一個函式')
print('func_obj函式物件: {}'.format(func_obj))
結果:
func_obj函式物件: <function func_obj at 0x7f9b6143f578>
解釋:
func_obj函式本身也是一個物件,儲存在記憶體中的地址為0x7f9b6143f578。
接上面示例:
func_obj()
func_test = func_obj
func_test()
結果:
這是一個函式
這是一個函式
解釋:
func_obj():正常的函式呼叫
func_test = func_obj: 將函式地址複製給func_test,這個和C裡面的函式指標是一樣的
func_test(): 執行函式func_obj
2.2函式中的函式(子函式)
顧名思義,函式的中的函式,即使在函式中再定義一個子函式,子函式的有效範圍只在當前函式內。
例如:
def internal_func():
'''
子函式示例函式
:return:
'''
print('子函式示例')
def hello():
print('this is hello function')
def test():
print('this is test funcion')
hello()
internal_func()
結果:
子函式示例
this is hello function
解釋:
def hello():在函式internal_func中定義一個子函式, 只能在internal_func函式內部中被呼叫。
雖然還定義了test函式,但是沒有呼叫,就不會執行test函式中的程式碼。
2.3將函式作為引數傳遞給另外一個函式
既然萬物接物件,那函式物件也可以作為引數傳遞給另外一個函式。
例如:
def func_param_func(func_param):
'''
執行func_param對應的引數
:param func_param: 函式物件
:return:
'''
print('執行{}函式'.format(func_param))
func_param()
func_param_func(func_obj)
結果:
執行<function func_obj at 0x7f9d1c527578>函式
這是一個函式
解釋:
func_param(): 其實這行程式碼和上面”萬物皆物件”裡面的示例程式碼一樣
func_obj()
func_test = func_obj
func_test()
2.4裝飾器函式
有了上面的知識儲備後,我們可以開始寫一個裝飾器了,裝飾器其實和”將函式作為引數傳遞給另外一個函式”原理是一樣的。
示例:
def func_trace(func):
'''
裝飾器函式,用於func函式名
:param func: 函式物件
:return:
'''
def wrapper(*args, **kwargs):
print('[func_trace]: enter {}()'.format(func.__name__))
return func(*args, **kwargs)
return wrapper
@func_trace
def add_func(a, b):
'''
整數相加
:param a:
:param b:
:return:
'''
sum = a + b
return sum
sum = add_func(1, 2)
print('add_func(1, 2) = {}'.format(sum))
結果:
[func_trace]: enter add_func()
add_func(1, 2) = 3
解釋:
def func_trace(func): 定義一個裝飾器函式, func為函式物件
def wrapper(*args, **kwargs):包裝器,args、kwargs是func函式的引數。
接下來時裝飾器函式自己的邏輯程式碼
return func(*args, **kwargs): 執行func函式。
@func_trace
def add_func(a, b):
定義了一個add_func函式,@func_trace為裝飾器,@func_trace相當於:
func_trace(add_func)
wrapper中的args = (1,2)
所以,return func(*args, **kwargs)就變成了:
return add(1,2)
2.5裝飾器類
裝飾器類和裝飾器函式實現的效果差不多是一樣的,但是類相對於函式來說能夠更加內聚,在類的內部能夠實現對應的成員函式和成員變數。
為了將裝飾器定義成一個例項,你需要確保它實現了__call__()和__get__()方法。 例如,下面的程式碼定義了一個類,它在其他函式上放置一個簡單的記錄層。
例如:
class Decorate(object):
'''
'''
def __init__(self):
'''
初始化
'''
print('Decorate init')
def __call__(self, func):
'''
:param func:
:return:
'''
def wrapper(*args, **kwargs):
print('[Decorate]: enter {}()'.format(func.__name__))
return func(*args, **kwargs)
return wrapper
@Decorate()
def sub_func(a, b):
'''
a - b
:param a:
:param b:
:return:
'''
return a - b
sum = sub_func(10, 2)
print('sub_func(10, 2) = {}'.format(sum))
結果:
[Decorate]: enter sub_func()
sub_func(10, 2) = 8
參考程式碼 :
https://github.com/minlixia/python(advanced/02_decorator.py)