我的Python成長之路---Day11-函式的使用及名稱空間和作用域
1.昨天函式的引數內容的補充
命名關鍵字引數: 在定義函式時,*與**之間引數稱之為命名關鍵字引數
特點:
在呼叫函式時,命名關鍵字引數必須按照key=value的形式傳值
def func(x,*,y=1,z): 在這裡*後邊的y和z都是命名關鍵字引數,y像預設引數一樣被事先賦值好了,再實 參進行傳值的時候可以不對y進行傳值 print(x) print(y) print(z) func(1,z=2) 傳值的時候必須要使用key=value的形式才可以傳值成功. def func(a,b=2,*args,c,**kwargs): 設定形參時各種形參的位置順序 print(a) print(b) print(args) print(c) print(kwargs)
------------------------------------------------------------------------------------分割線----------------------------------------------------------------------------
一、函式物件
函式是第一類物件: 指的是函式的記憶體地址可以像一個變數值一樣去使用
def foo(): #foo 不加括號代表函式的記憶體地址
print('from foo')
1. 變數值可以被引用
x=1 #foo=函式的記憶體地址
y=x
f=foo
print(f) 輸出:<function foo at 0x0000024CF6E63E18>
f() 輸出:from foo
2. 變數值可以當作引數傳給另外一個函式
def bar(x): 這時的x=foo
print(x) 將函式foo的記憶體地址打印出來
x() 相當於呼叫函式foo(),會實現foo的功能
bar(foo) 函式bar中的引數為函式foo(foo的記憶體地址)
3. 變數值可以當作函式的返回值
def func(x):
return x 將foo當做返回值返回
f=func(foo) 將foo當做引數傳給函式func,接受引數為foo時func的返回值
print(f) 其實這裡列印的還是foo的記憶體地址
4. 變數值可以當作容器型別中(容器型別指的是:元組、列表、字典)的元素
l=[foo,] 將foo當做列表中的元素
print(l) 輸出:[<function foo at 0x0000016828A43E18>]
l[0]() 使用列表的特點呼叫函式foo
dic={'1':foo} 將foo當做字典中的元素
print(dic)
dic['1']() 使用字典特點呼叫函式foo
-----------------------------------------------------------------------使用函式物件的第四個特點對簡易購物車進行優化--------------------------------
def register(): 前面定義函式實現相應的功能
print('註冊....')
def login():
print('登入....')
def pay():
print('支付....')
def transfer():
print('轉賬....')
func_dic={ 利用函式物件的第四個特點,將函式(記憶體地址)存放在字典中
'1':register,
'2':login,
'3':pay,
'4':transfer
}
#func_dic['1']() 可以使用這樣的形式直接呼叫相應功能的函式
'''
整體程式碼就不用寫特別長了,並且可拓展性相對於之前來說好了很多,想要新增什麼功能,直接定義函式實現功能的新增,然後在字典中新增新功能對應的鍵值對,再在列印階段打印出新功能的提示資訊就可以了,主程式碼並不需要改動即可實現新功能的新增
'''
while True:
print("""
0 退出
1 註冊
2 登入
3 支付
4 轉賬
""")
choice=input('請輸入你的操作: ').strip()
if choice == '0':break 這裡輸入0對應的操作程式碼不能喝下面的判斷程式碼互換位置,換了位
置之後就不能實現退出的功能,會被判定為為錯誤的指令輸入,因為字
典中的key沒有0
if choice not in func_dic:
print('輸錯的指令不存在') 判斷輸入的指令編號是否存在與字典中
continue
func_dic[choice]() 執行相應key對應的函式
二、函式巢狀
函式的巢狀呼叫:在一個函式內部又呼叫其他函式
def max2(x,y):
if x > y:
return x
else:
return y
def max4(a,b,c,d):
res1=max2(a,b) 在一個函式中又呼叫其他的函式
res2=max2(res1,c)
res3=max2(res2,d)
return res3
print(max4(1,2,3,4))
函式的巢狀定義: 在函式內又定義了其他函式
def func():
def foo(): 在func中巢狀定義函式foo
print('from foo')
# print(foo) 如果在這裡列印foo打印出來的是foo的記憶體地址
foo() 在func中也可以直接呼叫定義好的foo
x=1
print(x) 這裡x的值為1
func()
-------------------------------------------函式巢狀的使用---------------------------------
使用函式巢狀可以將同系列的函式功能統一到一個函式裡邊,簡化了函式的呼叫
下邊是一個函式巢狀的例子
from math import pi
def circle(radius,action): 可以直接通過引數來選擇來進行的操作,是要結算周長還是計算面積
def cal_perimeter():
return 2 * pi * radius
def cal_area():
return pi * (radius ** 2)
if action == 1:
res=cal_perimeter()
elif action == 2:
res=cal_area()
return res
res=circle(10,1)
print(res)
三、函式的名稱空間和作用域
一 、名稱空間相關
1. 名稱空間Namespaces:指的就是存放名字與值記憶體地址繫結關係的地方(記憶體空間)
x=1,需要在記憶體中申請一個空間來存放1這個值,同時還要尋找一個記憶體空間來儲存x和1的記憶體地址繫結關係的空間,存放名字與值對應繫結關係的地方就成為名稱空間,
2. 名稱空間分為三大類
內建名稱空間: 存放的是python直譯器自帶的名字(例如len()、print()、等等)
產生:python直譯器的啟動則產生
銷燬:python直譯器關閉則銷燬
全域性名稱空間: 在頂級程式碼中定義的名字
產生:執行python程式時產生
銷燬:python程式執行完畢後則銷燬
x=1
if True:
y=2
while True:
while True:
while True:
z=3 z=3在這裡也算做頂級程式碼中定義的名字,因為while迴圈是一直往下走的一直走到了z=3,相當於寫了一行程式碼,只不 過z=3寫在最後邊而已,也是存在於全域性名稱空間中的.
區域性名稱空間: 在函式內定義的名字
產生: 在函式呼叫時臨時產生
銷燬: 在函式呼叫完畢後則銷燬
def foo():
m=100 比如這裡的m就屬於區域性名稱空間中的,區域性名稱都是函式呼叫時臨時產生臨時銷燬的
foo()
三種名稱空間的產生的先後順序: 內建->全域性->區域性
查詢名字的順序:從當前位置往外一層一層查詢 查詢名字指的是在執行當前程式碼時,所需要用到的變數名的名字,並這行代 碼所在位置就是當前位置
如果當前在區域性名稱空間: 區域性->全域性->內建
如果當前在全域性名稱空間: 全域性->內建
# len=111
# def foo():
# # len=222
# print(len) 在這裡列印len的時候,首先從區域性名稱空間找,找到len=222,
# len=111 如果區域性空間len=222不存在,就從全部名稱空間找,可以找到len=111,
如果全部名稱空間的len=111不存在,就從內建名稱空間中找,這時候打印出來
的len就是python直譯器中求長度的函式len()的記憶體地址
# foo()
# x=0
def f1():
# x=1
def f2():
# x=2
def f3():
# x=3
print(x)
f3()
f2()
f1() 在f1()的最終結果中x=0,x=1,x=2,x=3都存在話,f1()的最終結果為x=3,如果從x=3.x=2,x=1,x=0一
次被註釋掉的時候,f1()的最終結果依次為3,2,1,0 這就是函式巢狀時尋找變數名的順序
def foo1():
def foo2():
def foo3():
print(x)
'''
二 、作用域:指的是作用範圍
全域性作用域:包含內建名稱空間與全域性名稱空間的名字
特點:全域性存活(該範圍內的名字會伴隨程式整個的生命週期,即從讀取出來到執行完畢關閉的時候),
全域性有效(在任何位置都能訪問的到)
區域性作用域:包含的是區域性名稱空間的名字
特點:臨時存活(只有在呼叫函式時生效,呼叫結束時失效)
區域性有效(只能在函式內使用)
作用域關係是在函式定義階段就已經固定死了,與呼叫位置無關
示範一:
def f1():
print(xxx)
xxx=111
def f2():
xxx=222
f1() 在這裡呼叫f1()時打印出來的值並不是222因為f1中xxx的值在定義階段已經被定義了xxx=111
無論在哪個地方呼叫f1,打印出來的值都是111
示範二:
xxx=111
def f1():
print(xxx) 這裡程式會進行報錯,原因是在定義階段已經就近找到了xxx的值為222但是在函式
呼叫階段又出現了xxx=111的情況,和定義的時候出現了衝突,去掉函式頭頂的
xxx=111即可正常使用函式,這時xxx的值為222
xxx=222
yyy=222
print(yyy) 這裡的yyy是可以正常輸出的,在定義階段yyy=222,呼叫函式的時候沒有與定義階
段衝突,但是如果在函式頭頂加上yyy=333時,呼叫時就會出現和xxx一樣的錯誤
f1()
(全域性/區域性)名稱空間:是存放值與變數名繫結關係的記憶體空間,是存(全域性/區域性)變數的地方
(全域性/區域性)作用域:指的是(全域性/區域性)變數起作用的範圍
(全域性/區域性)變數:存放在(全域性/區域性)名稱空間中,在程式碼中體現為全域性變數是在頂級程式碼的位置的,區域性變數是在函式體內部的
四、閉包函式
閉包函式:
閉:封閉,指的是該函式是定義一個函式內部的函式
包:該內部函式包含對外層函式名字(這裡的外層函式名字指的是外層函式包含的區域性變數)的引用
def outter(): inner在這裡就是一個典型的閉包函式,它定義在outter()內部,在inner
中使用的x屬於outter的區域性變數,也就是相對於inner來說的外部函式名
字的引用.
x=1
def inner():
print('from inner',x)
return inner
f=outter()
def foo():
# print(f)
x=111111111111111111111111111111111111
f() 在這呼叫f()時,x的值不會受到x=11111111111111111111111的影響,因為在f()定義階段
x=1
foo()
為函式體傳值的兩種方式:
def foo():
print('hello %s' %name)
方式一:直接以引數的形式傳入
def foo(name):
print('hello %s' %name)
foo('egon')
foo('egon')
foo('egon') 這種在呼叫的時候每次都要輸入要傳給引數的內容,呼叫的時候如果遇到要經常傳較長內容內參數的時候就會比較麻煩
方式二:閉包函式(使用閉包函式傳值給函式體)
def outter(name):
# name='egon'(省略了這一步)
def foo():
print('hello %s' %name)
return foo
f=outter('egon') 之後就可以直接呼叫f()就可以打印出來hello egon
# print(f)
f()
f()
f()
f1=outter('alex')
f1()
f1()
f1()
pip3 install requests 安裝python中爬蟲必要的元件,直接在cmd中輸入改命令就可以
閉包函式的簡單應用
import requests
問題 要給url傳值(也就是需要爬的網站名字)
def get():
response=requests.get(url)
if response.status_code == 200:
print(response.text)
解決方案一:(設定引數,給引數賦值)
def get(url):
response=requests.get(url)
if response.status_code == 200:
print(response.text)
get('https://www.baidu.com') 缺點:每次爬取都需要給引數url傳內容,呼叫比較麻煩
get('https://www.baidu.com')
get('https://www.baidu.com')
解決方案二:(使用閉包函式給url傳值)
def outter(url):
# url='https://www.baidu.com'
def get():
response=requests.get(url)
if response.status_code == 200:
print(response.text)
return get
baidu=outter('https://www.baidu.com') 一次傳值後賦值給變數名,以後可以重複使用
cnblogs=outter('https://www.cnblogs.com')
baidu()
baidu()
baidu()
baidu()
baidu()
baidu()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()