Python全棧之作用域和閉包
更新時間:2021年12月01日 16:01:10 作者:熬夜泡枸杞
這篇文章主要為大家介紹了Python作用域和閉包,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
1. return返回值
# ### return 自定義函數(shù)的返回值
"""
概念:return 把函數(shù)內(nèi)部的數(shù)據(jù)返回到函數(shù)的外面,返回到函數(shù)的調(diào)用處
1.return + 六大標(biāo)準(zhǔn)數(shù)據(jù)類型 , 除此之外還可以返回函數(shù) 或者 是類對象
2.return 在執(zhí)行時,意味著終止函數(shù),后面的代碼不執(zhí)行.
3.如果不定義return返回值,默認(rèn)返回None
"""
# (1) return + 六大標(biāo)準(zhǔn)數(shù)據(jù)類型
def func():
# return 111
# return 6.89
# return "你好帥啊,我愛死你樂"
# return [1,2,3]
# return {"a":1,"b":2}
return 1,2,3 # 返回元組
res = func()
print(res)
# (2) return 在執(zhí)行時,意味著終止函數(shù),后面的代碼不執(zhí)行.
def func():
print(1)
print(2)
return 3
print(4)
res = func()
print(res)
def func():
for i in range(5):
if i == 3:
return 4
print(i)
res = func()
print(res)
# (3) 如果不定義return返回值,默認(rèn)返回None
def func():
pass
res = func()
print(res) # None
# 注意點 打印的數(shù)據(jù)和返回的數(shù)據(jù)不是等價的,返回的數(shù)據(jù)是可以自定義的;
res = print(1234)
print(res) # None
# 模擬+-*/計算器
"""
功能: 完成計算
參數(shù): 2個數(shù)字和運算符
返回值: 計算后的結(jié)果
"""
def calc(num1,num2,sign):
if sign == "+":
return num1 + num2
elif sign == "-":
return num1 - num2
elif sign == "*":
return num1 * num2
elif sign == "/":
if num2 == 0:
return "除數(shù)不能為零"
return num1 / num2
else:
return "抱歉,超出了我的運算范圍."
res = calc(3,5,"+")
res = calc(3,5,"-")
res = calc(3,5,"*")
res = calc(3,0,"/")
res = calc(3,0,"&")
print(res)
2. 全局變量_局部變量
# ### 全局變量和局部變量 """ 1.概念 局部變量:在函數(shù)內(nèi)部定義的變量就是局部變量 全局變量:在函數(shù)外部定義的變量或者在函數(shù)內(nèi)部使用global關(guān)鍵字聲明是全局變量 2.作用域: 局部變量的作用范圍僅僅在函數(shù)的內(nèi)部 全局變量的作用范圍橫跨整個文件 3.生命周期:該變量的作用時長 內(nèi)置命名空間 -> 全局命名空間 -> 局部命名空間 (開辟空間順序) 內(nèi)置屬性 > 全局屬性 > 局部屬性 (作用時長:長->短) """ # 1 局部變量 def func(): # 定義一個局部變量 a = 1 # 獲取當(dāng)前的局部變量 print(a) # 修改一個局部變量 a = 2 print(a) func() # print(a) error # 2.全局變量 # 定義一個全局變量 b = 10 # 獲取當(dāng)前的全局變量 print(b) # 修改一個全局變量 b = 20 print(b) def func(): print(b) func() # 3.函數(shù)內(nèi)部定義全局變量 def func(): global c c =30 func() print(c) # 4.函數(shù)內(nèi)部修改全局變量 d = 50 def func(): global d d = 51 func() print(d) """ 總結(jié):global的使用 如果當(dāng)前不存在全局變量,可以在函數(shù)內(nèi)部通過global關(guān)鍵字來定義全局變量 如果當(dāng)前存在全局變量,可以在函數(shù)內(nèi)部通過global關(guān)鍵字來修改全局變量 """

3. 函數(shù)名的使用
# ### 函數(shù)名的使用
"""
# python中的函數(shù)可以像變量一樣,動態(tài)創(chuàng)建,銷毀,當(dāng)參數(shù)傳遞,作為值返回,叫第一類對象.其他語言功能有限
"""
def func():
print( "我是func函數(shù)")
# (1)動態(tài)創(chuàng)建
a = 1
print(a)
a = func
a()
# (2)動態(tài)銷毀
del a
# a()
# func()
# (3)當(dāng)參數(shù)傳遞
def func2():
return "我是func2函數(shù)"
def func1(f):
return f() # "我是func2函數(shù)"
res = func1(func2)
print(res)
# (4)作為值返回
def func3():
print( "我是func3函數(shù)" )
def func4(f):
return f
res = func4(func3)
print(res)
res()
print("<===>")
# (5)函數(shù)名可以作為容器類型數(shù)據(jù)的元素
lst = [func,func3]
for i in lst:
i()
print("<=========>")
# ### __doc__ 或者h(yuǎn)elp查看文檔
def big_chang_cishen(something):
"""
功能: 教你怎么吃大腸
參數(shù): 吃的內(nèi)容
返回值: 是否滿意
"""
print("把{}洗一洗".format(something))
print("直接找腸子頭,放嘴里,吸一下")
print("擦擦嘴,滿意的放下腸子頭")
return "吃完了,真好吃~"
big_chang_cishen("生腸子")
# 方法一
res = big_chang_cishen.__doc__
print(res)
# 方法二
help(big_chang_cishen)
4. 函數(shù)的嵌套
4.1 函數(shù)的嵌套
# ### 函數(shù)的嵌套
"""
互相嵌套的兩個函數(shù)
:
包裹在外層的叫做外函數(shù),內(nèi)層的就是內(nèi)函數(shù)
"""
def outer():
# inner()
def inner():
print("我是inner函數(shù)")
""""""
# (1)內(nèi)部函數(shù)可以直接在函數(shù)外部調(diào)用么 不行
# inner()
# (2)調(diào)用外部函數(shù)后,內(nèi)部函數(shù)可以在函數(shù)外部調(diào)用嗎 不行
# outer()
# inner()
# (3)內(nèi)部函數(shù)可以在函數(shù)內(nèi)部調(diào)用嗎 可以
outer()
# (4)內(nèi)部函數(shù)在函數(shù)內(nèi)部調(diào)用時,是否有先后順序 有的
# 先定義在調(diào)用
# 在其他語言中有預(yù)加載的機(jī)制,提前把函數(shù)駐留到內(nèi)存中,然后再去編譯腳本內(nèi)容
# python沒有預(yù)加載函數(shù)的機(jī)制,只能先定義在調(diào)用;
# 外函數(shù)是outer 中間函數(shù)是inner 最里層是smaller ,調(diào)用smaller函數(shù)
def outer():
def inner():
def smaller():
print("我是smaller函數(shù)")
smaller()
inner()
outer()
# LEGB 原則
def outer():
def inner():
def smaller():
print(a)
smaller()
inner()
outer()
"""
LEGB原則(就近找變量原則)
#找尋變量的調(diào)用順序采用LEGB原則(即就近原則)
B —— Builtin(Python);Python內(nèi)置模塊的命名空間 (內(nèi)建作用域)
G —— Global(module); 函數(shù)外部所在的命名空間 (全局作用域)
E —— Enclosing function locals;外部嵌套函數(shù)的作用域(嵌套作用域)
L —— Local(function);當(dāng)前函數(shù)內(nèi)的作用域 (局部作用域)
依據(jù)就近原則,從下往上 從里向外 依次尋找
"""



4.2 nonlocal的使用
# ### nonlocal的使用 (用來修改局部變量) """ nonlocal遵循LEGB原則 (1) 它會找當(dāng)前空間上一層的變量進(jìn)行修改 (2) 如果上一層空間沒有,繼續(xù)向上尋找 (3) 如果最后找不到,直接報錯 """ # (1)它會找當(dāng)前空間上一層的變量進(jìn)行修改 def outer(): a = 10 def inner(): nonlocal a a = 20 print(a) inner() print(a) outer() # (2)如果上一層空間沒有,繼續(xù)向上尋找 def outer(): a = 20 def inner(): a = 15 def smaller(): nonlocal a a = 30 print(a) smaller() print(a) inner() print(a) outer() # (3)如果最后找不到,直接報錯 """nonlocal 只能修改局部變量,""" """ a = 20 def outer(): def inner(): def smaller(): nonlocal a a = 30 print(a) smaller() print(a) inner() print(a) outer() error """ # (4) 不通過nonlocal 是否可以修改局部變量呢?ok def outer(): lst = [1,2,3] def inner(): lst[-1] = 3000 inner() print(lst) outer()
5. 閉包函數(shù)的定義
# ### 閉包函數(shù)
"""
互相嵌套的兩個函數(shù),如果內(nèi)函數(shù)使用了外函數(shù)的局部變量
并且外函數(shù)把內(nèi)函數(shù)返回出來的過程,叫做閉包
里面的內(nèi)函數(shù)叫做閉包函數(shù)
是不是閉包?
1.內(nèi)函數(shù)用了外函數(shù)的那個局部變量
2.外函數(shù)返回內(nèi)函數(shù)
"""
# 1.基本語法形式
def zhaoshenyang_family():
father = "馬云"
def hobby():
print("我對錢沒有一絲絲的興趣,我不看重錢,這是我爸爸{}說的".format(father))
return hobby
func = zhaoshenyang_family()
func()
print("<==1==>")
tup = func.__closure__
print(tup[0].cell_contents) # 馬云
print(tup)
print("<==2==>")
# 2.閉包的復(fù)雜形式
def zhaowanli_family():
gege = "王思聰"
didi = "鞋王,高振寧"
money = 1000
def gege_hobby():
nonlocal money
money -= 500
print("我交朋友不在乎他有沒有錢,反正都沒有我有錢.我就喜歡交女朋友... 錢物還剩下{}".format(money))
def didi_hobby():
nonlocal money
money -= 400
print("家里有鞋柜,各式各樣的奢侈鞋,一雙大概20~30萬,錢物還剩下{}".format(money))
def big_master():
return [gege_hobby,didi_hobby]
return big_master
func = zhaowanli_family()
print(func)
lst = func()
print(lst)
# 獲取哥哥函數(shù)
gege = lst[0]
gege()
# 獲取弟弟函數(shù)
didi = lst[1]
didi()
# 3.使用 __closure__ , cell_contents 判定閉包
"""如果返回的元組中有數(shù)據(jù)說明是閉包,誰的生命周期被延長就打印誰"""
tup = func.__closure__
print(tup)
# 先獲取第一個單元格 cell_contents獲取對象中的內(nèi)容
func1 = tup[0].cell_contents
print("<11111>")
"""打印閉包函數(shù)didi_hobby中,生命周期被延長的屬性"""
print(func1.__closure__[0].cell_contents)
func1()
# 在獲取第二個單元格 cell_contents獲取對象中的內(nèi)容
func2 = tup[1].cell_contents
print("<22222>")
"""打印閉包函數(shù)gege_hobby中,生命周期被延長的屬性"""
print(func2.__closure__[0].cell_contents)
func2()



6. 閉包的特點_意義
# ### 閉包特點 """ 特點:在閉包函數(shù)中,內(nèi)函數(shù)使用了外函數(shù)的局部變量, 該變量會與內(nèi)函數(shù)發(fā)生綁定,延長該變量的生命周期, 持續(xù)到腳本執(zhí)行結(jié)束. """ def outer(val): def inner(num): return val + num return inner func = outer(10) res = func(15) print(res) # ### 閉包的意義 """全局變量的作用域大,容易被篡改""" num = 0 def click_num(): global num num += 1 # num = num + 1 print(num) click_num() click_num() click_num() num = 100 click_num() click_num() # 改造,用閉包來實現(xiàn) """ 閉包的意義: 閉包可以優(yōu)先使用外函數(shù)中的變量,并對閉包中的值起到了封裝保護(hù)的作用.外部無法訪問. """ def outer(): x = 0 def click_num(): nonlocal x x += 1 print(x) return click_num click_num = outer() click_num() click_num() click_num() x = 100 click_num() click_num()
小提示:
def outer():
a = 10
def inner():
a = 20
print(a)
inner()
print(a)
outer()
這里的輸出結(jié)果是20 10,嵌套里的兩個a變量互不干擾
列表可以直接可以在內(nèi)外函數(shù)直接傳遞值,修改列表
的時候不需要使用nolocal來修改變量的值。
閉包可以延長局部變量的周期
沒辦法在函數(shù)的內(nèi)部去修改一個全局變量的,必須通過一個global(跟nonlocal一個道理的)
7. 小練習(xí)
# # 1.定義函數(shù):接收任意個參數(shù),打印其中的最小值
def func(*args):
lst = []
for i in args:
if isinstance(i , (float,int)):
lst.append(i)
print(lst)
return lst[0]
res = func(-100,1,2,423,"sdf")
print(res)
# 2.定義函數(shù):傳入一個參數(shù)n,返回n的階乘(5! = 5*4*3*2*1)
def func(n):
total = 1
for i in range(n,0,-1):
total *= i
return total
print(func(5))
# 3.寫函數(shù),傳入函數(shù)中多個實參(均為可迭代對象如字符串,列表,元祖,集合等)
# # 將容器中的每個元素依次添加到新的列表中返回
#例:傳入函數(shù)兩個參數(shù)[1,2,3] (22,33)最終args為(1,2,3,22,33)
# 方法一
def func(*args):
lst =[]
for i in args:
for j in i:
lst.append(j)
return lst
res = func([1,2,3],(5,6,7),"abc")
print(res)
# 方法二
def func(*args):
return list(args)
res = func(*[1,2,3],*(5,6,7),*"abc")
print(res)
# 4.寫函數(shù),用戶傳入要修改的文件名,與要修改的內(nèi)容,執(zhí)行函數(shù),修改操作
# 方法一
def func(filename,str1,str2):
with open(filename,mode="r+",encoding="utf-8") as fp:
strvar = fp.read()
print(strvar)
res = strvar.replace(str1,str2)
with open(filename,mode="w+",encoding="utf-8") as fp:
fp.write(res)
func("ceshi2.py","內(nèi)置函數(shù)","外置函數(shù)")
# 方法二
def func(filename,str1,str2):
with open(filename,mode="r+",encoding="utf-8") as fp:
strvar = fp.read()
res = strvar.replace(str1,str2)
# print(fp.tell())
fp.seek(0)
# 清空
fp.truncate()
fp.write(res)
func("ceshi2.py","外置函數(shù)","內(nèi)置函數(shù)")
# 5.寫函數(shù),計算傳入字符串中【數(shù)字】、【字母】、【空格] 以及 【其他】的個數(shù)
# 方法一
def func(strvar):
dic = {"num":0,"word":0,"space":0,"other":0}
for i in strvar:
if i.isdecimal():
dic["num"] += 1 # dic["num"] = dic["num"] + 1
elif i.encode().isalpha():
dic["word"] += 1
elif i.isspace():
dic["space"] += 1
else:
dic["other"] += 1
return dic
# strvar = input("請輸入字符串")
# print(func(strvar))
"""
print("你".isalpha())
# 中文 => False
print("你".encode().isalpha())
# 字母 => True
print("a".encode().isalpha())
"""
# 方法二
def func(strvar):
dic = {"num":0,"word":0,"space":0,"other":0}
lst = []
for i in range(97,123):
lst.append(chr(i))
lst.append(chr(i-32))
for i in strvar:
if i in "0123456789":
dic["num"] += 1
elif i in lst:
dic["word"] += 1
elif i == " ":
dic["space"] += 1
else :
dic["other"] += 1
return dic
# strvar = input("請輸入字符串")
# print(func(strvar))
# 6.寫函數(shù),檢查字典的每一個value的長度,如果大于2,那么僅保留前兩個長度的內(nèi)容,返回處理后的結(jié)果.
#例:參數(shù)為:dic = {"k1": "v1v1", "k2": [11,22,33,44]}
def func(dic):
if isinstance(dic,dict):
for k,v in dic.items():
print(k,v)
dic[k] = v[:2]
return dic
else:
return "不是字典"
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
print(func(dic))
print(func([1,23,42,34,23,4234]))
# 7傳入多個容器類型數(shù)據(jù),計算所有元素的個數(shù)
def func(*args):
total = 0
for i in args:
print(i)
total += len(i)
return total
res = func("123",[5,6,7],("你好","123423"))
print(res)
# 改造,不去判斷字符串本身的長度
def func(*args):
total = 0
for i in args:
print(i)
if isinstance(i,str):
total += 1
elif isinstance(i,(tuple,list,set,dict)):
total += len(i)
return total
res = func("123",[5,6,7],("你好","123423"))
print(res)
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Python3.5 Pandas模塊之Series用法實例分析
這篇文章主要介紹了Python3.5 Pandas模塊之Series用法,結(jié)合實例形式分析了Python3.5中Pandas模塊的Series結(jié)構(gòu)原理、創(chuàng)建、獲取、運算等相關(guān)操作技巧與注意事項,需要的朋友可以參考下2019-04-04
Django model重寫save方法及update踩坑詳解
這篇文章主要介紹了Django model重寫save方法及update踩坑詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
python讀取與處理netcdf數(shù)據(jù)方式
今天小編就為大家分享一篇python讀取與處理netcdf數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
python實現(xiàn)應(yīng)用程序在右鍵菜單中添加打開方式功能
這篇文章主要介紹了python實現(xiàn)應(yīng)用程序在右鍵菜單中添加打開方式功能,本文分步驟給大家介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友參考下吧2017-01-01
python通過shutil實現(xiàn)快速文件復(fù)制的方法
這篇文章主要介紹了python通過shutil實現(xiàn)快速文件復(fù)制的方法,涉及Python中shutil模塊的使用技巧,需要的朋友可以參考下2015-03-03
Python實現(xiàn)的手機(jī)號歸屬地相關(guān)信息查詢功能示例
這篇文章主要介紹了Python實現(xiàn)的手機(jī)號歸屬地相關(guān)信息查詢功能,涉及Python文件讀取及基于第三方接口調(diào)用查詢信息的相關(guān)操作技巧,需要的朋友可以參考下2017-06-06

