日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python带参数装饰器 函数名_python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)...

發布時間:2023/12/2 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python带参数装饰器 函数名_python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、函數名應用

函數名是什么?函數名是函數的名字,本質:變量,特殊的變量。

函數名(),執行此函數。

python 規范寫法

1. #后面加一個空格,再寫內容,就沒有波浪線了。

2.一行代碼寫完,下面一行的的內容要空2行,

3.逗號2個邊的內容要有空格。

如果是不規范的寫法,Pycharm編輯器,會有灰色的波浪線顯示。

1.單獨打印函數名

def func1():

print(666)

print(func1)

執行輸出:

打印的是一個函數內存地址

2.函數名的賦值

def func2():

print(666)

f = func2

print(f())

執行輸出:

666

None

3.函數名可以作為容器類數據的元素

下面的函數都要執行

def f1():

print(111)

def f2():

print(222)

def f3():

print(333)

def f4():

print(444)

寫4個執行代碼就可以了

f1()

f2()

f3()

f4()

如果是100個呢?

使用for循環批量執行函數

def f1():

print(111)

def f2():

print(222)

def f3():

print(333)

def f4():

print(444)

l1 = []

for i in range(1, 5):

l1.append('f' + str(i))

for i in l1:

eval(i)()

執行輸出:

111

222

333

444

4.函數名可以作為參數

def f1():

print(666)

def f2(x):

x()

f2(f1)

執行輸出:

666

分析如下:

def f1():

print(666)

def f2(x): # x = f1

x() # f1()

f2(f1) #將f1函數作為變量傳參給f2,x()表示執行函數f1(),輸出666

5.函數名可以作為函數的返回值。

def f11(x):

return x #將返回值傳給調用者f11(5),此時ret = 5

ret = f11(5)

print(ret)

執行輸出:

5

def f1():

print(666)

def f2(x):

return x

f2(f1)()

執行輸出:

666

代碼分析:

def f1():

print(666)

def f2(x): # x = f1

return x #將f1返回給函數調用者f2(f1),此時就相當于 f1 = f2(f1)

f2(f1)() #將f1函數作為變量傳參給f2,return之后f2(f1)等于f1,f1()就表示執行f1函數,輸出666

f1是一個特殊變量,加()就可以執行了

第一類對象( first-class object)指

1.可在運行期創建

2.可用作函數參數或返回值

3.可存入變量的實體

*不明白?那就記住一句話,就當普通變量用

函數名就是第一類對象

加括號,就可以執行了。

二、閉包

閉包函數:

內部函數包含對外部作用域而非全劇作用域變量的引用,該內部函數稱為閉包函數

有如下代碼,請補全代碼,在函數外部執行inner()函數

def wrapper():

def inner():

print(666)

第一種寫法

def wrapper():

def inner():

print(666)

inner()

wrapper()

執行輸出:

666

第二種寫法

def wrapper():

def inner():

print(666)

return inner #將inner函數返回給調用者ret,此時ret = inner

ret = wrapper()

ret() #執行inner函數

執行輸出:

666

ret = wrapper()

ret()

等同于

wrapper()()

return inner之后,inner由臨時空間,轉換為全局空間了。

因為ret賦值了

閉包舉例

def wrapper():

name = '老男孩'

def inner():

print(name)

inner()

wrapper()

執行輸出:

老男孩

如何判斷它是否是一個閉包函數呢??內層函數名.__closure__? cell 就是=閉包

def wrapper():

name = '老男孩'

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

執行輸出:

老男孩

(,)

出現了cell,就表示它是一個閉包函數

name = '老男還'

def wrapper():

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

執行輸出:

老男還

None

返回值為None 表示它不是閉包

因為name是一個全局變量

如果函數調用了外層變量而非全局變量,那么它就是閉包

name = '老男還'

def wrapper2():

name1 = 'alex'

def inner():

print(name)

print(name1)

inner()

print(inner.__closure__)

wrapper2()

執行輸出:

老男還

alex

(,)

只要引用了外層變量至少一次,非全局的,它就是閉包

面試題:

下面的函數,是一個閉包嗎?

name = '老男孩'

def wraaper2(n):

# n = '老男孩' 相當于

def inner():

print(n)

inner()

print(inner.__closure__) # None

wraaper2(name)

它也是一個閉包

雖然wraaper2傳了一個全局變量,但是在函數wraaper2內部,inner引用了外層變量,相當于在函數inner外層定義了n = '老男孩',所以inner是一個閉包函數

閉包的好處

當函數開始執行時,如果遇到了閉包,他有一個機制,他會永遠開辟一個內存空間,將必包中的變量等值放入其中,不會隨著函數的執行完畢而消失。

舉一個例子

from urllib.request import urlopen

content = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')

print(content)

執行輸出,是一堆網頁源代碼。

爬3次

from urllib.request import urlopen

content1 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')

content2 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')

content3 = urlopen('http://www.xiaohua100.cn/index.html').read().decode('utf-8')

內存開了3次,很占用內存

把它封裝成閉包

from urllib.request import urlopen

def index():

url = "http://www.xiaohua100.cn/index.html"

def get():

return urlopen(url).read()

return get

xiaohua = index()

content = xiaohua()

print(content)

這個例子,只有第一遍,是從網站抓取的。

之后的執行,直接從內存中加載,節省內存空間

三、裝飾器初識

裝飾器本質上就是一個python函數,他可以讓其他函數在不需要做任何代碼變動的前提下,增加額外的功能,裝飾器的返回值也是一個函數對象。

裝飾器的應用場景:比如插入日志,性能測試,事務處理,緩存等等場景。

現在我有一個需求,我想讓你測試這個函數的執行時間,在不改變這個函數代碼的情況下:

先寫一個雛形

import time

def func1():

print('in func1')

time.sleep(1) # 模擬程序邏輯

start = time.time()

func1()

print(time.time() - start)

執行輸出:

in func1

1.0001070499420166

封裝成函數

傳一個參數,函數名,就可以查看函數的執行時間了

import time

def func1():

print('in func1')

time.sleep(1) # 模擬程序邏輯

def timmer(f):

start_time = time.time()

f()

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

timmer(func1)

執行輸出:

in func1

此函數的執行時間為1.0002098083496094

原來100個函數,都是調用了func1(),現在測試函數,需要timeer(func1)。如果想測試所有調用地方的執行時間,那么需要修改100個函數位置,改成timeer(func1),太麻煩了。

不能更改原來的調用方式,同時需要加一個函數執行時間的功能。怎么辦呢?

要無限接近于原來的調用方法,慢慢來

先來講一個變量賦值的例子

a = 1

b = a

a = 2 #a重新賦值了,原來a的值不存在了。但是b還是等于原來a的值,也就是1

print(a,b)

執行輸出2,1

1.更改執行方式

import time

def func1():

print('in func1')

time.sleep(1) # 模擬程序邏輯

def timmer(f):

start_time = time.time()

f()

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

f1 = func1 #定義f1等于func1函數

func1 = timmer #定義func1等于timmer,等式計算右邊的。此時func1被覆蓋了,和原來的沒有任何關系,f1還是等于原來的func1

func1(f1) #此時相當于執行 timmer(老的func1)

執行輸出:

in func1

此函數的執行時間為1.0001263618469238

在精簡一步

import time

def func1():

print('in func1')

time.sleep(1) # 模擬程序邏輯

def timmer(f): # f = func1

def inner():

start_time = time.time()

f() #執行func1()

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner #將inner函數返回給函數調用者timmer(func1)

a = timmer(func1) #等式計算右邊的,將func1函數傳給timmer函數

a() #此時相當于執行了inner函數

執行輸出:

in func1

此函數的執行時間為1.000577449798584

最終版本

import time

def timmer(f): # 2接收參數.f = func1

def inner():

start_time = time.time() #5.進入inner函數

f() #6.執行f(),也就是原來的func1函數。雖然func1被覆蓋了,但是之前的值還存在。請參考上面a,b賦值的例子

end_time = time.time() #10 獲取當前時間

print('此函數的執行時間為{}'.format(end_time - start_time)) #11.輸出差值

return inner #3.將inner函數返回給函數調用者timmer(func1),此時程序結束,繼續執行func1()

def func1(): #7.進入函數

print('in func1') # 8.打印輸出

time.sleep(1) # 9.等待1秒

func1 = timmer(func1) #1.等式計算右邊的,將func1函數傳給timmer函數,此時func1被覆蓋了,原來func1的不存在了。

func1() #4.這里的func1是全新的func1,就是上面的賦值,此時相當于執行 inner函數

代碼從上至下執行,先加載函數變量timmer和func1。在執行上文說的第1步以及后面的,請看數字。

執行輸出:

in func1

此函數的執行時間為1.0009608268737793

但是加這一步,還是不太方便。那么python給這種情況,加了一個語法糖@

語法糖指那些沒有給計算機語言添加新功能,而只是對人類來說更"甜蜜"的語法

import time

def timmer(f): # f = func1

def inner():

start_time = time.time()

f() #執行func1()

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner #將inner函數返回給函數調用者timmer(func1)

#語法糖@

@timmer #相當于 func1 = timmer(func1) #這一步就已經覆蓋了

def func1():

print('in func1')

time.sleep(1) # 模擬程序邏輯

func1() #相當于執行了inner()函數

想測試誰,前面加@裝飾器函數,即可。

裝飾器利用return制造了一個假象,func1()執行,其實是執行了inner()

func1()已經把原來的func1()給覆蓋了

這個裝飾器,還不夠完整,函數不能傳參數

先來舉個例子

def func2(a1,b1): #4.執行函數,接收位置參數a1=1,b1=2

print(a1,b1) #5. 輸出1,2

def func3(a,b): #2. 接收參數,a=1,b=2

func2(a,b) #3. 執行函數func2(1,2)

func3(1,2) #1.傳位置參數1,2

執行輸出:

1 2

func3執行一遍后,將a,b的值,傳給a1,b1了

上面裝飾器的例子,func1,要傳2個參數a,b

import time

def timmer(f):

def inner(a,b):

start_time = time.time()

f(a,b)

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner

@timmer

def func1(a,b):

print('in func1 {}{}'.format(a,b))

time.sleep(1) # 模擬程序邏輯

func1(1,2)

執行輸出:

in func1 12

此函數的執行時間為1.0006024837493896

如果有多個參數呢?改成動態參數

import time

def timmer(f):

def inner(*args,**kwargs):

start_time = time.time()

f(*args,**kwargs)

end_time = time.time()

print('此函數的執行時間為{}'.format(end_time - start_time))

return inner

@timmer

def func1(*args,**kwargs):

print('in func1 {}{}'.format(args,kwargs))

time.sleep(1) # 模擬程序邏輯

func1(1,2,a='3',b=4)

執行輸出:

in func1 (1, 2){'b': 4, 'a': '3'}

此函數的執行時間為1.000101089477539

面試題,手寫一個裝飾器

寫裝飾器,約定俗成,函數名為wrapper

第一步

def wrapper(func):

def inner():

func()

return inner

第二步

def wrapper(func):

def inner(*args,**kwargs):

func(*args,**kwargs)

return inner

第三步

def wrapper(func):

def inner(*args,**kwargs):

'''被裝飾函數之前'''

ret = func(*args,**kwargs)

'''被裝飾函數之后'''

return ret

return inner

完整的

def wrapper(func):

def inner(*args,**kwargs):

'''被裝飾函數之前'''

ret = func(*args,**kwargs)

'''被裝飾函數之后'''

return ret

return inner

@wrapper

def func(*args,**kwargs):

print(args,kwargs)

return 666

print(func())

作業:

使用函數完成用戶登錄和注冊功能

#先讓用戶選擇,是登陸還是注冊

#選擇序號完畢之后,運行相應的程序,

#驗證成功之后,可以讓其繼續選擇,登陸還是注冊,還可以選擇退出。

1.先準備函數的雛形

def registered_username(username):

'''

#判斷注冊用戶名是否存在

:param username: 用戶名

:return: True 存在 False 不存在

'''

def write_file(username,password):

'''

#寫入用戶列表文件

:param username: 用戶名

:param password: 密碼

:return: True 寫入成功 False 寫入失敗

'''

def username_password(username,password):

'''

#判斷用戶名和密碼是否匹配

:param username: 用戶名

:param password: 密碼

:return: True 匹配成功 False 匹配失敗

'''

def register(*args,**kwargs):

'''

注冊邏輯

:return:

'''

pass

def login(*args,**kwargs):

'''

登錄邏輯

:return:

'''

pass

def user_menu(*args,**kwargs):

'''

# 用戶菜單

'''

pass

2.先寫菜單

def user_menu(*args,**kwargs):

'''

# 用戶菜單

'''

# 判斷文件是否存在,不存在創建文件

file_exists()

# 循環

while True:

# 打印菜單

menu = ['注冊', '登錄', '退出']

print('bbs系統'.center(25, '#'))

for i in range(len(menu)):

print('{}\t{}'.format(i + 1, menu[i]))

print(''.center(27, '#'))

number = input('請選擇序號: ').strip()

if number == '1':

# 執行注冊程序

register()

elif number == '2':

# 執行登錄程序

login()

elif number == '3':

exit()

else:

print('輸入錯誤,請重新輸入!')

3.寫判斷用戶列表文件是否存在

def file_exists(*args,**kwargs):

'''

# 判斷用戶列表文件是否存在

:return: True 存在 False 不存在

'''

# 判斷文件是否存在

if os.path.exists(file_name):

return True

else:

with open(file_name, encoding='utf-8', mode='w') as mk:

mk.write('張三 123')

return False

4.再寫注冊邏輯

def register(*args,**kwargs):

'''

注冊邏輯

:return:

'''

while True:

username = input('請輸入注冊的用戶名,或輸入q返回菜單:').strip()

if username == '':

print('用戶名為空,請重新輸入!')

elif username.upper() == 'Q':

break

else:

# 執行判斷用戶名函數

result = registered_username(username)

if result:

password = input('請輸入您的注冊的密碼:').strip()

# 判斷密碼

if password == '':

print('密碼為空,請重新輸入!')

else:

# 執行寫入用戶列表文件函數

result = write_file(username, password)

if result:

print('注冊成功!,您的用戶名為: {}\n倒計時2秒返回菜單!'.format(username))

time.sleep(2)

user_menu()

else:

print('注冊失敗!請重試')

else:

print('用戶名已經存在,請重新輸入!')

5.判斷注冊用戶名是否可用

def registered_username(username):

'''

#判斷注冊用戶名是否可用

:param username: 用戶名

:return: True 可用(用戶不存在) False 不可用(用戶已存在)

'''

# 純用戶名列表,不包含密碼

user_list = []

with open(file_name, encoding='utf-8') as f1:

for i in f1:

# 去空格,以空格切割,轉換為列表

li = i.strip().split() # [張三,123]

# 將用戶名追加到列表中

user_list.append(li[0])

# 判斷用戶名是否存在列表中

if username in user_list:

# 返回False

return False

else:

return True

6.寫入用戶列表文件

def write_file(username,password):

'''

#寫入用戶列表文件

:param username: 用戶名

:param password: 密碼

:return: True 寫入成功 False 寫入失敗

'''

with open(file_name, encoding='utf-8', mode='a') as f2:

f2.write('\n{} {}'.format(username, password))

return True

7.登錄邏輯

def login(count=0,max=3):

'''

登錄邏輯

:param count: 初始失敗次數

:param max: 最大失敗次數

:return:

'''

while count < max:

count += 1

username = input('請輸入用戶名:').strip()

password = input('請輸入密碼:').strip()

# 執行驗證用戶名和密碼函數

result = username_password(username,password)

if result:

print('登陸成功\n倒計時1秒返回菜單!')

time.sleep(1)

user_menu()

break

else:

print('用戶名或密碼錯誤,還剩余{}次機會!'.format(max - count))

# 返回主菜單

user_menu()

8.判斷用戶名和密碼是否匹配

def username_password(username,password):

'''

#判斷用戶名和密碼是否匹配

:param username: 用戶名

:param password: 密碼

:return: True 匹配成功 False 匹配失敗

'''

# print(username,password)

with open(file_name, encoding='utf-8', mode='r') as f3:

for i in f3:

# print(i)

# 去空格,以空格切割,轉換為列表

li = i.strip().split() # [張三,123]

# 判斷用戶名和密碼是否匹配

if username == li[0] and password == li[1]:

result = True

# 當找到匹配時,跳出循環

break

else:

result = False

# 當整個用戶列表遍歷完成之后,再return

return result

最終完整代碼如下:

# -*- coding: utf-8 -*-

import time,os

#文件名

file_name = 'user_list.txt'

def file_exists(*args,**kwargs):

'''

# 判斷用戶列表文件是否存在

:return: True 存在 False 不存在

'''

# 判斷文件是否存在

if os.path.exists(file_name):

return True

else:

with open(file_name, encoding='utf-8', mode='w') as mk:

mk.write('張三 123')

return False

def registered_username(username):

'''

#判斷注冊用戶名是否可用

:param username: 用戶名

:return: True 可用(用戶不存在) False 不可用(用戶已存在)

'''

# 純用戶名列表,不包含密碼

user_list = []

with open(file_name, encoding='utf-8') as f1:

for i in f1:

# 去空格,以空格切割,轉換為列表

li = i.strip().split() # [張三,123]

# 將用戶名追加到列表中

user_list.append(li[0])

# 判斷用戶名是否存在列表中

if username in user_list:

# 返回False

return False

else:

return True

def write_file(username,password):

'''

#寫入用戶列表文件

:param username: 用戶名

:param password: 密碼

:return: True 寫入成功 False 寫入失敗

'''

with open(file_name, encoding='utf-8', mode='a') as f2:

f2.write('\n{} {}'.format(username, password))

return True

def username_password(username,password):

'''

#判斷用戶名和密碼是否匹配

:param username: 用戶名

:param password: 密碼

:return: True 匹配成功 False 匹配失敗

'''

# print(username,password)

with open(file_name, encoding='utf-8', mode='r') as f3:

for i in f3:

# print(i)

# 去空格,以空格切割,轉換為列表

li = i.strip().split() # [張三,123]

# 判斷用戶名和密碼是否匹配

if username == li[0] and password == li[1]:

result = True

# 當找到匹配時,跳出循環

break

else:

result = False

# 當整個用戶列表遍歷完成之后,再return

return result

def register(*args,**kwargs):

'''

注冊邏輯

:return:

'''

while True:

username = input('請輸入注冊的用戶名,或輸入q返回菜單:').strip()

if username == '':

print('用戶名為空,請重新輸入!')

elif username.upper() == 'Q':

break

else:

# 執行判斷用戶名函數

result = registered_username(username)

if result:

password = input('請輸入您的注冊的密碼:').strip()

# 判斷密碼

if password == '':

print('密碼為空,請重新輸入!')

else:

# 執行寫入用戶列表文件函數

result = write_file(username, password)

if result:

print('注冊成功!,您的用戶名為: {}\n倒計時2秒返回菜單!'.format(username))

time.sleep(2)

user_menu()

else:

print('注冊失敗!請重試')

else:

print('用戶名已經存在,請重新輸入!')

def login(count=0,max=3):

'''

登錄邏輯

:param count: 初始失敗次數

:param max: 最大失敗次數

:return:

'''

while count < max:

count += 1

username = input('請輸入用戶名:').strip()

password = input('請輸入密碼:').strip()

# 執行驗證用戶名和密碼函數

result = username_password(username,password)

if result:

print('登陸成功\n倒計時1秒返回菜單!')

time.sleep(1)

user_menu()

break

else:

print('用戶名或密碼錯誤,還剩余{}次機會!'.format(max - count))

# 返回主菜單

user_menu()

def user_menu(*args,**kwargs):

'''

# 用戶菜單

'''

# 判斷文件是否存在,不存在創建文件

file_exists()

# 循環

while True:

# 打印菜單

menu = ['注冊', '登錄', '退出']

print('bbs系統'.center(25, '#'))

for i in range(len(menu)):

print('{}\t{}'.format(i + 1, menu[i]))

print(''.center(27, '#'))

number = input('請選擇序號: ').strip()

if number == '1':

# 執行注冊程序

register()

elif number == '2':

# 執行登錄程序

login()

elif number == '3':

exit()

else:

print('輸入錯誤,請重新輸入!')

# 執行菜單

user_menu()

執行輸出:

總結

以上是生活随笔為你收集整理的python带参数装饰器 函数名_python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。