1. 程式人生 > 其它 >Python入門到逆襲7(進階篇1)

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

  • 引數題外話 : (一般專案團隊都會做的一些約束)
  1. 引數預設不超過5個(超過5個會進行壓棧)
  2. 所有外部輸入引數,都需要做引數型別、有效值校驗

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)