Python-12
@(Python)
一、函數對象
- 函數是第一類對象,意思是函數可以被當做數據處理
- 函數對象:就是函數不帶括號
- 函數對象,可以將定義在函數內的函數,通過
return返回值,返回到全局中使用,從而打破函數的層級限制- Python中一切皆對象
func和func()的區別
func()是函數的返回值func函數名記錄了值的內存地址(記錄了值的內存地址,相當於連接函數名和值的線),函數名就是函數的內存地址print(func)打印的是func函數名記錄的值的內存地址print(func())打印的是func函數的返回值

① 函數名可以被用來引用(賦值給一個變量)
# func是一個函數
y=x
f=func
print(f) # 就相當於print(func)
f() # f()就相當於func()調用函數
② 函數名當做參數傳給一個函數

③ 函數名可以當做函數的返回值

④ 函數名可以當做容器類型的元素
可以把函數的內存地址(或理解為函數名的內存地址),當做元素

利用函數名為容器類型的元素,來調用函數
# 取款
def qk():
print('取款成功')
# 轉賬
def zz():
print('轉賬成功')
# 支付
def zf():
print('支付成功')
func_dict={
'1':qk,
'2':zz,
'3':zf,
}
while True:
msg='''
1. 取款
2. 轉賬
3. 支付
4. 退出
'''
print(msg)
func_num=input('輸入數字>>')
if func_num == '4' : break
if func_num not in func_dict:
print('不在范圍')
continue
func_dict[func_num]()
二、函數的嵌套
1. 函數的嵌套定義
- 函數的嵌套是在函數中再定義函數
- 在函數內中定義的函數,只能在這個函數內使用(一般情況下)
def func1():
def func2():
print('函數2')
- 通過函數嵌套,將一個大功能的小功能嵌套進去,不同的功能匯聚到一起,類似於封裝成一個工具箱
- 例子:利用函數嵌套和函數對象當做容器元素,來寫出計算圓面積和周長的功能
from math import pi # 計算圓的公式需要調用
def yuan(banjing,action):
def mianji():
return pi * (banjing ** 2)
def zhouc():
return pi * banjing * 2
if action == 'mianji':
return mianji() # 這是yun函數的返回值
elif action == 'zhouc':
return zhouc()
func1=input('半徑>>')
func1=int(func1)
func2=input('計算類型>>')
print(yuan(func1,func2)) # 也可以使用默認形參固定一個常用的類型
2. 函數的嵌套調用
- 使用函數嵌套,在調用一個函數時,也調用了其他函數
- 如果一個功能可以被重復調用,就可以單獨做成一個功能,使用其他函數再調用

三、名稱空間與作用域
1. 名稱空間
- 專門用來存名字的空間(變量名、函數名等的內存地址)
- 名稱空間,是存放名字和值綁定關系的地方
① 內置名稱空間
- 內置命名空間:Python解釋器自帶的名字
- 生命周期:在解釋器啟動時生效,在解釋器關閉時失效
② 全局名稱空間
- 全局名稱空間:除了內置和局部空間外,其余都是全局名稱空間
- 全局名稱空間,是在文件執行時產生的(頂頭寫的代碼使用的就是全局名稱空間)
- 生命周期:在文件執行時生效,在文件執行完畢后失效
③ 局部名稱空間
- 存放函數調用期間函數體產生的名字,即函數內定義的名字
- 生命周期:執行文件時,只有被調用了才會臨時生效,在函數執行完畢后失效,自動釋放
內置、全局、局部名稱空間的加載順序
① 內置名稱空間--->② 全局名稱空間--->③ 局部名稱空間
內置、全局、局部名稱空間的查找順序
① 局部名稱空間--->② 全局名稱空間--->③ 內置名稱空間- 基於當前位置,然后按順序找


2. 作用域
- 作用域就是名稱空間的作用的范圍,是對名稱空間的再分類
① 全局作用域
- 全局作用域:就是全局作用范圍,包括:內置名稱空間和全局名稱空間
- 全局有效:內置命名空間和全局命名空間
- 全局存活:從程序開始存活,一直到程序的結束
② 局部作用域
- 局部作用域:就是局部作用范圍,包括:局部命名空間
- 局部有效,臨時存活
- 作用域關系是在函數定義階段就固定好了,但凡要調用函數就需要去函數的定義階段找作用域關系

x=10
def func1():
print(x)
x=10000000000000000000000
def func2():
x=11111111111
func1()
func2() # 以調用為分隔符,往前找


x=10
def func1():
x=777777777777777777 # 先找局部空間,再找全局空間,全局空間有多個找上面最近的
print(x)
x=10000000000000000000000
def func2():
x=11111111111
func1()
func2() # 以調用為分隔符,往前找
③ 作用域的應用:
- 打破層級限制,利用
return將函數名轉到全局,再調用


def f1():
def inner():
print('from inner')
return inner
f1()() # f1()得到的是return的值,相當於inner,f1()() == inner()
# 或者
f=f1()
f() # 相當於f1()()

def f1():
x=1
def inner():
print('from inner',x)
return inner
f=f1() # 相當於f=inter
def bar():
x=11111111111111
f() # 相當於inter()
bar()
- 說明:回到定義階段,按照先局部,后全局的順序找,如果局部沒有才找全局,如果有多個全局,就以調用函數為分隔線,往上找最近的
- 在函數體內,改全局的東西,需要使用
global x,比如global x將x拿到全局用,同代碼段往下找最后一個- 但是盡量不要改全局,盡量做成獨立的功能,對其他無影響
x=1
def foo():
global x
x=111
foo()
print(x)
nonlocal會往本函數體外層找,往上找最近的,但是還是在大的函數內,找到就改,找不到就報錯
x=1
def f1():
def f2():
x=2222222 # 找到的內容
def f3():
nonlocal x
x=111111111111 # 要改成什么
f3()
print(x) # 打印這一層的,看nonlocal是后生效
f2()
f1()

- 在局部如果想要修改全局的可變類型,不需要借助任何聲明,可以直接修改,比如可以改字典,列表等
- 在局部如果想要修改全局的不可變類型,需要借助
global聲明,聲明為全局的變量就可以直接修改

