1. 程式人生 > 實用技巧 >函式總結(全)

函式總結(全)

#!/usr/bin/env python3 
# ­*­ coding: utf­8 ­*­

################1.0函式基礎################
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、什麼是函式
函式就相當於具備某一功能的工具
函式的使用必須遵循一個原則:
先定義
後呼叫
2、為何要用函式
1、程式碼冗餘,程式的組織結構不清晰,可讀性差
2、可維護性、擴充套件性差
3、如何用函式
先定義
三種定義方式
後呼叫
三種呼叫方式
返回值
三種返回值的形式

"""
# 1、先定義
# #定義的語法
"""
def 函式名(引數1,引數2,...):
###文件描述####
函式體
return值

"""
########形式一:無參函式##########

# def func():
# print('孔維鑫 is a GOOdboy')
#
# func()
#####重點!!!!!!!!!!!
# 定義函式發生的事情
# 1、申請記憶體空間 存數體程式碼
# 2,將上述記憶體地址繫結 數名
# 3、定義函式不會執行函式體程式碼,但是會檢測函式體語法


# 呼叫函式發生的事情
# 1、通過函式名找到 數的內tt址
# 2、然後加口號就是在觸發函式體程式碼的執行
# print(func)
# func()

# 示範1
# def bar():#bar=函式的記憶體地址 1
# print("from bar")
#
# def foo():
# # print(bar)
# bar()
# print('from foo')
# foo()


# 示範2

# def foo():
# # print(bar)
# bar()
# print('from foo')
# foo() #會報錯 因為此時bar未定義
# def bar(): # bar=函式的記憶體地址 1
# print("from bar")
#
# foo()#不會報錯


########形式二:有參函式##########
# 例如 print() open() input() list()

# def func(x,y):
# print(x,y)
# func(1,2)


########形式三:空函式##########

# def func(x,y):
# pass

"""
函式怎麼用 ???
舉例說明:
如果你想在統計三個年級的每個年級學生人數中做一個加法運算計算各年級總體人數
正常情況我們應該是
比如:
一年級:
男生1=20
女生1=30
一年級總人數=男生1+女生1
print("一年級總計人數為:-----{}".format(一年級總人數))
二年級
男生2=30
女生2=30
二年級總人數=男生2+女生2
print("二年級總計人數為:-----{}".format(二年級總人數))
三年級
男生3=50
女生3=30
三年級總人數=男生3+女生3
print("三年級總計人數為:-----{}".format(三年級總人數))

總人數=一年級總人數+二年級總人數+三年級總人數
print(總人數)

但是每次這樣進行計算確實比較複雜,所以用函式就可以解決這這個問題

def p_number(boy,girl):
總計人數=boy+girl
print("總計男女人數為:-----{}".format(總計人數))
return 總計人數

一年級人數 = p_number(20,30)
二年級人數 = p_number(30,30)
三年級人數 = p_number(50,30)

總人數=一年級人數+二年級人數+三年級人數
print(總人數)

這樣就可以進行多次利用
"""

# 三種定義方式各用何處
# 1,無參函式的應用場景
# 接收使用者輸入資訊
# name= input("username>>>:")
# age = input("user age>>>:")
# msg='名字:{}年齡:{}'.format(name,age)
#

# 但是如果是要輸入三十次呢??

# def interactive():
# name = input("username>>>:")
# 而且還可以在函式裡面新增其他內容
# age = input("user age>>>:")
# msg = '名字:{}年齡:{}'.format(name, age)
# print(msg)

# interactive()
# interactive()
# interactive()
# interactive()
# 2,有參函式的應用場景
# 相加函式
# def add(x,y):
# res=x+y
# print(res)

# 傳統做法
# x = 20
# y = 30
# res = x+y
# print(res)

# 換句話說 :如果函式是工場 那引數相當於加工材料

# 3,空函式的應用場景 #構思的時候

# 我們可能想到的功能有使用者認證,下載,上傳,瀏覽,切換目錄等功能,可以先做出如下定義:
# def auth_user():
# """user authentication function"""
# pass
#
# def download_file():
# """download file function"""
# pass
#
# def upload_file():
# """upload file function"""
# pass
#
# def ls():
# """list contents function"""
# pass
#
# def cd():
# """change directory"""
# pass


# 二 呼叫函式
# 1.0 語句的形式:只去呼叫函式,不做其他操作
# interactive()

# 2.0表示式函式
# def add(x,y):#引數-》原材料
# res=x+y
# return res#返回值-》產品]

# 賦值表示式
# res=add(1,2)
# print(res)

# 數學表示式
# res=add(1,2)*10
# print(10)

# 3.0函式呼叫可以當做引數
# def add(x, y): # 引數-》原材料
# res = x + y
# return res # 返回值-》產品]
#
# res=add(add(1,2),10)
# print(res)


# 三,函式返回值
# return是函式結束的標誌,即函式體程式碼一旦執行到return
# 會立刻終止函式的執行,並且會將return後的值當做本次執行的結果返回:

# 之前的需求
# def func(x,y):
# print('1111')
# print('2222')
# print('3333')
# res =x+y #res = 1+2
# return res
# res = func(1,2)
# print(res)

# 性質:函式體程式碼一旦執行到return會立刻終止函式的執行
# def func():
# print(1111)
# return # 後面就算是while 也會結束 (一般用的是break)
# print(2222)
# print(3333)
#
#
# func()


# 1.返回none:函式體內沒有return
# return
# return None

# def func():
# pass
# res= func()
# print(res)

# def func():
# return None
# res= func()
# print(res)


# 2.返回一個值: (return 值)
# def func():
# return 10
# res = func()
# print(res)


# 3.返回多個值: (return +多個值): 用逗號分隔開多個值,會被return返回成元組
# def func():
# return 10, "kwx", [1, 2] # 返回值元組 不用加括號
#
#
# res = func()
# print(res, type(res))


"""

說白了,函式就是一種工具,
舉個例子: 一個機器人 | (你們之前做過ardunio的簡單的微控制器設計可以知道 所有功能都會變成一個個函式 進行單獨使用)

假如這個機器人腦子裡啥都是空的就等你輸入功能

首先 : 我們是不是先進行構思
第一,是不是要讓機器人會動起來吧 怎麼動!!!!
定義空函式
def feet(): 腳怎麼動
pass
def hands(): 手怎麼動
pass
def arms(): 胳膊怎麼動
pass
def head(): 頭怎麼動
pass

等等
內容是看自己的需求來進行確定的!!!!!!(程式設計師常說的一句話"看情況!!!")

這裡舉個例子:
我們知道我們寫過9x9乘法表
for i in range (1,10):
for j in range(1,i+1):
print("{}x{}={}".format(i,j,i*j),end=" ")
print()

那現在的需求就是輸入幾 就輸出他之前的所有的乘法表
如果沒函式的寫法:
(第一種)直接改for i in range (1,10):裡的範圍
eg: 前五的乘法表
for i in range (1,5):
for j in range(1,i+1):
print("{}x{}={}".format(i,j,i*j),end=" ")
print() #這種是不是每次都會改數字啊是不是很麻煩!!!!
(第二種)在第一種基礎上優化 每次改太複雜,會不會用到一個input()進行簡化賦值
n = int(input("親輸入你要輸出的值:"))
# print(type(n))#<class 'str'>這輸出的是字串那是不是就要進行轉化啊!!! 怎麼轉的 是不是想到int()!!!!(你應該想到的)
for i in range(1,n+1): #吧範圍進行變數賦值!! 注意我們知道這裡是左閉右開 所以n是需要加1的 n+1
for j in range(1, i + 1):
print("{}x{}={}".format(i, j, i * j), end=" ")


(第三種)一行解決 如果內建函式掌握了的話
print('\n'.join([' '.join(["%2s x%2s = %2s"%(j,i,i*j) for j in range(1,i+1)]) for i in range(1,10)]))

自己看看 !!!都學過!!! 資料型別內建函式裡面的

雖然已經很好了但是大家在看用函式寫的是啥樣的
<普通> 將重複部分進行加到函式中
def num(n):
for i in range (1,n+1): #重
for j in range(1,i+1): #復 直接寫到函式中
print("{}x{}={}".format(i,j,i*j),end=" ") #部
print() #分
num(5)



<第三對應> 十分簡潔
def num(n):
return '\n'.join([' '.join(["%2s x%2s = %2s" % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, n+1)])
print(num(5))

"""

#############2.0函式引數使用#############
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
函式引數的使用
一,形參與實參介紹

二,形參與實參的具體使用
2.1位置引數
2.2關鍵字引數
2.3 預設引數
2.4可變長度的引數(*與**的用法)
2.4.1可變長度的位置引數
2.4.2可變長度的關鍵字引數
2.5命名關鍵字引數(瞭解)
2.6組合使用(瞭解)

"""
# 一,形參與實參介紹
# 含義:
"""
形參:在定義函式階段定義的引數稱之為形式引數,簡稱形參 相當於變數名
def func(x,y): #x=1 y=2
print(x,y)


實參:在呼叫函式階段傳入的值稱之為實際引數,簡稱實參,相當於變數值
func(1,2)

print(x,y) #繫結關係只在函式體內進行

#形參與實參的關係:
#1.0 在呼叫階段,實參(相當於變數值)會繫結(賦值=繫結記憶體地址)給形參(相當於變數名)
#2.0 這種繫結關係只能在函式體內使用
# 3.0 實參與形參的繫結關係在函式呼叫時生效,函式呼叫結束後解除繫結關係

實參是傳入的值,但值可以是以下形式
形式一: 直接給值
func(1,2)
形式二:變數形式
a=1
b=2
func(a,b)

#形式三:func(int(2)
func(func1(1.2,),func2(2.3)333)
說白了只要是值就行 是什麼無關 基本資料型別都可以!!!
"""

"""
二,形參與實參的具體使用
2.1位置引數:按照從左到右的順序依次定義的引數稱之為位置引數
1>位置形參:在函式定義階段,按照從左到右的順序直接定義的"變數名"
特點:特點:必須被傳值,多一個不行少一個也不行
def func(x,y):
print(x,y)
func()
func(1,2)
func(1,2,3)
2>位置實參:在函式呼叫階段,按照從左到有的順序依次傳值
特點: 按照順序與形參-對應
func(1,2)
func(2,1)

2.2關鍵字引數
關鍵字實參:在函式呼叫階段,按照key=value的形式傳入的值
特點:指名道姓給某個形參傳值,可以完全不參照順序
def func(x,y)
print(x,y)

func(y=2,x=1)

#注意:混合使用,強調
# 1、位置實參必須放在關鍵字實參前
def func(x,y)
print(x,y)
func(1,y=2)
func(y=2,1)
# 2、不能為同一個形參重複傳值
# func(1,y=2,x=3)
# func(1,2,x=3, y=4)

2.3 預設引數(預設形參引數)

#預設形參:在定義函式階段,就已經被賦值的形參,稱之為預設引數
特點:在定義階段就已經被賦值,意味著在呼叫階段可以不用為其賦值
def func(x,y=3): y=3就是預設的
print(x,y)
func(x=1)
#func(x=1) #輸出結果:1 3
func(x=1, y=44444)#輸出結果:1 44444 # 以你想傳的為準

#那什麼時候用位置形參 那什麼時候用預設形參呢!!!

位置形參:是必須要傳值的,所以當函式必須要有值的時候就用到位置形參!!

預設形參:在呼叫時候是要經常改變值,但不會改變函式本身,就可以進行設定為預設實參

# 舉例:
# 比如機械班的同學進行資訊輸入(我們知道乃是眾星捧月之式 女的很少)
def register(name,age,sex):
print(name,age sex)

register('三炮",18,'男")
register('二炮',19,'男)
register('大炮',19,'男)
register('沒炮',19,'女')
# 這樣定義是不是太複雜 因為女的就比較少輸入會變得很複雜重複 ,那怎麼辦呢!!!

def register(name,age,gender="男"):
print(name,age,gender)

register('三炮',18)
register('二炮',19)
register('大炮',19)
register('沒炮',19,gender="女")

#位置形參與預設形參混用,強調:
#1、位置形參必須在預設形參的左邊
#def func(y=2,x):
# pass

# 2、預設引數的值是在函式定義階段被賦值的, 準確地說被賦予的是值的記憶體地址.

def func(x,y=2):
print(x,y)
func(1)# 輸出值預設是1 2
# 示例1
如果 這麼寫呢
m=2
def func(x,y=2): #y=-->2的記憶體地址
print(x,y)
m=333333
func(1)

輸出結果呢!!! --->輸出結果是 1 2 所以你可以知道 是在定義函式前進行賦值才可以

但是如果是這樣的呢

m=[1111]
def func(x,y=m): #y=-->[1111]的記憶體地址
print(x,y)
m.append(2222)
func(1) #輸出結果:1 [1111, 2222]

# 所以準確地說被賦予的是值的記憶體地址
# 雖然預設值可以被指定為任意資料型別,但是不推薦使用可變型別
m=[1111]
def func(x,y=m): #y=-->[1111]的記憶體地址
print(x,y)
m.append(2222)
func(1) #輸出結果:1 [1111, 2222]



def func(x,y,z,l=None):
if l is None:
l=[]
l. append (x)
l. append(y)
l. append(z)
print(l)

func(1,2,3)

#所有在這裡說一嘴 你在定義函式時 是最好是可以滿足所有的變化在函式內進行 (就是不能受其他的影響)

2.4可變長度的引數(*與**的用法)
# 什麼是可變長度:可變長度指的是在呼叫函式時,傳入的值(實參)的個數不固定
#而實參是用來為形參賦值的,所以對應著,針對溢位的實參必須有對應的形參來接收


2.4.1可變長度的位置引數
#1:形參格式(*形參名):用來接收溢位的位置實參,溢位的位置實參會被*儲存成元組的格式,然後賦值給形參

def func(x,y,*z):
print(x,y,z)
func(1,2,3,4,5,6)

def my_sum(*args): #通常為 *args(規定)
res=0
for item in x:
res+=item
return res
res=my_sum(1,2,3,4.5,6)
print(res)
#II:*可以用在實參中,實參中帶* ,先*後的值打散成位置實參

# def func(x,y,z):
# print(x,y,z)
# # func(*[11,22,33])## func(11, 22..33)
# l=[11,22,33]
# func(*l)
# 或
# l=[11,22,33]
# func(*l)


#III:形參與實參中都帶*
def func(x,y,*args):#args=(3,4,5,6)
print(x,y,args)
func(1,2,[3,4,5,6])
func(1,2,*[3,4,5,6])#func(1,2,3,4,5,6)


2.4.2可變長度的關鍵字引數
#1:形參格式(**形參名):用來接收溢位的關鍵字實參,溢位的位置實參會被*儲存成字典的格式,然後賦值給形參
**後跟的可以是任意名字,但是約定俗成應該是kwargs


def func(x,y,** kwargs):
print(x,y,kwargs)
# func(1,y=2,a=1,b=2,c=3)
func(*[11,22,33]) #func(11,22,33)

#II:*可以用在實參中,實參中帶** ,先**後的值打散成關鍵字實參

def func(x,y,z):
print(x,y,z)
# func(*{'x':1,'y':2,'z':3}) #func(x=1,y=2)
# func(** {'x':1,'y':2,'z':3})#func(x=1,a=2,z=3)
#錯誤

# func(*{'x':1,'y':2,})#func(x=1,y=2) #不能少
# TypeError: func() missing 1 required positional argument: 'z'
# TypeError:func()缺少1個必需的位置引數:“ z”
func(**{'x':1,'a':2,'z':3})#func(x=1,a=2,z=3) #不能多

# TypeError: func() got an unexpected keyword argument a
# TypeError:func()獲得了意外的關鍵字引數a





#III:形參與實參中都帶**

def func(x,y,**kwargs):
print(x,y,kwargs)
# func(y=222, x=111, a=333, b=444)
func(**{'y':222,'x':111,'a':333,'b':4444,})

#混用*與**時:#*args必須在**kwargs之前
# 示例 1
def func(*args,**kwargs):
print(args)
print(kwargs)
func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)


# 示例2
def index(x,y,z,bbb):
print("index=>>>",x,y,z,bbb)
def wrapper(a,b,c,d):#a=1,b=2,c=3
index(a,b,c,d)#index(1,2,3)
wrapper(1,2,3,4)#wrapper的傳遞引數是給index用的# 也就是index()牽制wrapper()函式引數!!!

def index(x,y):
print(x,y)
def wrapper(*args, **kwargs):# args=(1,) kwargs={'y':2, 'z':3}
index(*args,**kwargs)
# index(*(1,),**{'y':2, 'z':3})
# index (1, z=3, y=2)
wrapper(y=2,z=3,x=1,)#不會被牽制但是要遵循index()的形參進行賦值實參






2.5命名關鍵字引數(瞭解)
#1,命名關鍵字引數(瞭解)
#命名關鍵字引數:在定義函式時,*後定義的引數,如下所示,
#特點:
#1、命名關鍵字實參必須按照key-value的形式為其傳值
# 1
def func(x,y,*,a,b):#其中a和b稱之為命名關鍵字引數
print(x,y)
print(a,b)
# func(1,2,b=222,a=111)
#2
def func(x,y,*,a,b=2222):#其中a和b稱之為命名關鍵字引數
print(x,y)
print(a,b)
func(1,2)

def func(x,y,*,a=11111,b):
print(x.y)
print(a.,b)
#func(1,2)

|||||||瞭解||||||||||||||
在定義了**kwargs引數後,函式呼叫者就可以傳入任意的關鍵字引數key=value,
如果函式體程式碼的執行需要依賴某個key,必須在函式內進行判斷
def register(name,age,**kwargs):
if 'sex' in kwargs:
#有sex引數
pass
if 'height' in kwargs:
#有height引數
pass

想要限定函式的呼叫者必須以key=value的形式傳值,Python3提供了專門的語法:
需要在定義形參時,用作為一個分隔符號,號之後的形參稱為命名關鍵字引數。對於這類引數,
在函式呼叫時,必須按照key=value的形式為其傳值,且必須被傳值
def register(name,age,*,sex,height): #sex,height為命名關鍵字引數
pass

register('lili',18,sex='male',height='1.8m') #正確使用
register('lili',18,'male','1.8m') # TypeError:未使用關鍵字的形式為sex和height傳值
register('lili',18,height='1.8m') # TypeError沒有為命名關鍵字引數height傳值。

命名關鍵字引數也可以有預設值,從而簡化呼叫
def register(name,age,*,sex='male',height):
print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height))

register('lili',18,height='1.8m')
#輸出結果:Name:lili,Age:18,Sex:male,Height:1.8m

需要強調的是:sex不是預設引數,height也不是位置引數,因為二者均在後,所以都是命名關鍵字引數,
形參sex=’male’屬於命名關鍵字引數的預設值,因而即便是放到形參height之前也不會有問題。

另外,如果形參中已經有一個args了,命名關鍵字引數就不再需要一個單獨的*作為分隔符號了
def register(name,age,*args,sex='male',height):
print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height))

register('lili',18,1,2,3,height='1.8m') #sex與height仍為命名關鍵字引數
#輸出結果: Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m
||||||||||||||||||||||||||||||||||||||||||||||||


2.6 組合使用(瞭解)
#形參順序:位置新參,預設形參,*args,命名關鍵字形參,**kwargs

def func(x,y=111,*args,z,**kwargs):
print(x)
print(y)
print(args)
print(z)
print(kwargs)



# 實參用法:
func(1)
func(x=1)
func(1,x=1)
func(*'hello')
func(**{})
func(*'hell'**{})





















綜上所述所有引數可任意組合使用,但定義順序必須是:位置引數、預設引數、args、命名關鍵字引數、*kwargs
可變引數*args與關鍵字引數kwargs通常是組合在一起使用的,如果一個函式的形參為*args與kwargs,
那麼代表該函式可以接收任何形式、任意長度的引數
def wrapper(*args,**kwargs):
pass


在該函式內部還可以把接收到的引數傳給另外一個函式(這在裝飾器的實現中大有用處)
def func(x,y,z):
print(x,y,z)

def wrapper(*args,**kwargs):
func(*args,**kwargs)

wrapper(1,z=3,y=2)
#輸出結果:1 2 3
按照上述寫法,在為函式wrapper傳參時,其實遵循的是函式func的引數規則,呼叫函式wrapper的過程分析如下:
1. 位置實參1被接收,以元組的形式儲存下來,賦值給args,即args=(1,),關鍵字實參z=3,y=2被*接收,
以字典的形式儲存下來,賦值給kwargs,即kwargs={'y': 2, 'z': 3}
2. 執行func(args,kwargs),即func((1,),* {'y': 2, 'z': 3}),等同於func(1,z=3,y=2)
提示: *args、**kwargs中的args和kwargs被替換成其他名字並無語法錯誤,但使用args、kwargs是約定俗成的。

"""

############3.0函式名稱和作用域#############
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、名稱空間(namespaces)
I:三種名稱空間用途與存活週期
II:三種名稱空間的載入順序
III:三種名稱空間的查詢名字的優先順序
2、作用域全域性作用域區域性作用
global
Local
函式巢狀使用的情況下,作用域與名字的查詢關係

(後續補上)
4、函式物件

5、閉包函式


"""
# 1,名稱空間namespace:存放名字的地方,是對棧區的劃分
# 在編寫程式是的變數名的儲存在棧區的空間 對名字進行歸類為三種:如果不分類 同樣的名字會被覆蓋(之前說過)

# x =10

"""
棧區 堆區

內建名稱空間|
(全域性範圍:內建,全域性)| x->0xfffff0030---------------> 10(0xfffff0030) #x=10
全域性名稱空間|

區域性名稱空間
就把棧區當地球 名稱空間:就當國家
假設:內建當做美國 全域性為中國
你叫tom 但是你在中國 美國中也有叫tom的
但: 你們不是同一個人!!!!


有了名稱空間之後,就可以在樓區中存放相同的名字,詳細的,
名稱空間分為三種:

#1.1內建各稱空間 一個
#存放的名字: 存放的python直譯器內建的名字 例如:print input open 都是內建函式名
>>> print
<built-in function print> #built-in :內建
>>> input
<built-in function input>
#存活週期:python直譯器啟動則產生,python直譯器關閉則銷燬

#1.2全域性名稱空間 一個
#存放的名字:只要不是函式內定義的,也不是內建的,剩下的就是全域性名稱空間

比如 :
import os 全域性名稱
x=10
if 13>3:#全域性名稱
y=20
if 3==3:#全域性名稱
z=30

#func=函式的記憶體地址
def func():#全域性名稱空間
a=111
b=222

class Foo:: #全域性名稱空間
pass

#存活週期:python檔案執行時新產生,python檔案執行完畢後銷燬



#1.3區域性名稱空間 多個
#存放的名字:在呼叫函式時,執行函式體程式碼過程中產生的函式內的名字
#存活週期:在呼叫函式時存活,函式呼叫完畢後則銷燬
def func():
a=111
b=222
func()
func()
func()
func()
# 民稱空間有幾個???? ---> 四個 函式呼叫幾次產生幾個名稱空間
# def func(a,b):
# pass
#名稱空間 四個
# func(10,1)
# func(11,12)
# func(13,14)
# func(15,16)

#1.4名稱空間的載入順序
# 內建名稱空間 > 全域性名稱空間 > 區域性名稱空間
#(python直譯器)(python檔案) (定義的函式)
# 內建 全域性是一定有 區域性不一定有



#1.5銷燬順序
#區域性名稱空間 > 全域性名稱空間 > 內建名稱空間

# 名稱空間 不是真實存在的 真正存在的是棧區 棧區進行劃分的結果就是名稱空間

#1.6名字的查詢優先順序:當前所在的位置向上一層一層查詢
#內建名稱空間
#全域性名稱空間
#區域性名稱空間

#如果當前在區域性名稱空間:
#區域性名稱空間->全域性名稱空間->內建名稱空間

例項1:
#當尋找input的在區域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
input=333
def func():
input=444
print(input) # 區域性是不是存在input啊 可知:input=444
#所以你輸出的必然是input=444
func()

例項2
#當尋找input的在不在區域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
# 是不是應在去全局裡面找啊
input=333
def func():
print(input) # 區域性不存在input啊 可知:全域性input=333
#所以你輸出的必然是input=333
func()

# 例項3
#當尋找input的在不在區域性,也不在全域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
# 是不是應在去內建裡面找啊

def func():
print(input) # 區域性不存在input啊 全局裡也沒input
#所以你輸出的必然是input在內建函式裡面的input()函式!!!
func()

# 故輸出結果是:<built-in function input>



#如果當前在全域性名稱空間
#全域性名稱空間->內建名稱空間

# 原理同上
input=333
def func():
input=444
func()
print(input)#全域性名稱空間進行查詢

# 示範1
def func():
print(x)
x=111
func()

def func():
print(x)

func()
x=111
#示範2:名稱空間的關係 區域性名稱空間(省份) > 全域性名稱空間(國家) > 內建名稱空間(地球)
# 名稱空間的"巢狀"關係是以函式定義階段為準,與呼叫位置無關
x=1
def func():
print(x)

def foo():
x=222
func()
foo()

#示範3:函式巢狀定義
#這裡是為了講解 使用input進行賦值 正常情況不要這麼寫!!!

input=111
def f1():
input=222
def f2():
input=333
print(input)
f2()
f1()




# 示範4
x=111
def func():
print(x)
x=222
func()


# 名字的查詢順序是從定義階段為準的 然後進行每層查詢的 (區域性名稱空間->全域性名稱空間->內建名稱空間)
但是在分析的時候要從定義階段為基準進行每層分析.,

"""
"""
2、作用域-->作用範圍
#全域性作用域:內建名稱空間、全域性名稱空間
特點:
1,全域性存活
2,全域性有效:被所有函式共享
# # 自定義函式不能相互找(除非相互巢狀)
def foo():
x=111
print(x)
def bar():
y=222
print(y)
foo()
bar()

#區域性作用域
特點:
1,臨時存活
2,區域性有效:只在自己的函式(區域性名稱空間)內有效
def foo(x):
def f1():
def f2():
print(x)



# 多個名稱空間為了方便定義有一個方法:LEGB(區域性名稱空間)(!!!!!!!瞭解內容)

# 三,global與 nonLocal
# global:
# 例項1 x=111 與x=222 無關,因為一個是全域性 一個是區域性
x=111
def func():
x=222
func()
print(x)

#例項2 如果在區域性想要修改全域性的名字對應的值,需要用global(要求是不可變型別)
x=111
def func():
global x #申明x為全域性名字 x=222為-到了全域性名稱空間會把111改成222
x=222
func()
print(x)


# 例項3 (可變型別)
l=[111,222]
def func():
l.append()
func()
print(l)


# nonlocal(瞭解):修改函式外層函式包含的名字對應的值(不可變型別)
# 例項1
def f1():
x=11
def f2():
global x
x=22
f2()
print("f1內的x:",x)
f1()

# 例項2

def f1():
x=11
def f2():
nonlocal x #若x=11不存在的 則報錯 若存在 則就改變外層x=11的值
x=22
f2()
print("f1內的x:",x)
f1()

"""
###########4.0函式物件和閉包函式##########
# -*- coding: utf-8 -*-
# @Time:
# @Auther: kongweixin
# @File:
"""
1、名稱空間(namespaces)
I:三種名稱空間用途與存活週期
II:三種名稱空間的載入順序
III:三種名稱空間的查詢名字的優先順序
2、作用域全域性作用域區域性作用
global
Local
函式巢狀使用的情況下,作用域與名字的查詢關係

(後續補上)
4、函式物件

5、閉包函式


"""
# 1,名稱空間namespace:存放名字的地方,是對棧區的劃分
# 在編寫程式是的變數名的儲存在棧區的空間 對名字進行歸類為三種:如果不分類 同樣的名字會被覆蓋(之前說過)

# x =10

"""
棧區 堆區

內建名稱空間|
(全域性範圍:內建,全域性)| x->0xfffff0030---------------> 10(0xfffff0030) #x=10
全域性名稱空間|

區域性名稱空間
就把棧區當地球 名稱空間:就當國家
假設:內建當做美國 全域性為中國
你叫tom 但是你在中國 美國中也有叫tom的
但: 你們不是同一個人!!!!


有了名稱空間之後,就可以在樓區中存放相同的名字,詳細的,
名稱空間分為三種:

#1.1內建各稱空間 一個
#存放的名字: 存放的python直譯器內建的名字 例如:print input open 都是內建函式名
>>> print
<built-in function print> #built-in :內建
>>> input
<built-in function input>
#存活週期:python直譯器啟動則產生,python直譯器關閉則銷燬

#1.2全域性名稱空間 一個
#存放的名字:只要不是函式內定義的,也不是內建的,剩下的就是全域性名稱空間

比如 :
import os 全域性名稱
x=10
if 13>3:#全域性名稱
y=20
if 3==3:#全域性名稱
z=30

#func=函式的記憶體地址
def func():#全域性名稱空間
a=111
b=222

class Foo:: #全域性名稱空間
pass

#存活週期:python檔案執行時新產生,python檔案執行完畢後銷燬



#1.3區域性名稱空間 多個
#存放的名字:在呼叫函式時,執行函式體程式碼過程中產生的函式內的名字
#存活週期:在呼叫函式時存活,函式呼叫完畢後則銷燬
def func():
a=111
b=222
func()
func()
func()
func()
# 民稱空間有幾個???? ---> 四個 函式呼叫幾次產生幾個名稱空間
# def func(a,b):
# pass
#名稱空間 四個
# func(10,1)
# func(11,12)
# func(13,14)
# func(15,16)

#1.4名稱空間的載入順序
# 內建名稱空間 > 全域性名稱空間 > 區域性名稱空間
#(python直譯器)(python檔案) (定義的函式)
# 內建 全域性是一定有 區域性不一定有



#1.5銷燬順序
#區域性名稱空間 > 全域性名稱空間 > 內建名稱空間

# 名稱空間 不是真實存在的 真正存在的是棧區 棧區進行劃分的結果就是名稱空間

#1.6名字的查詢優先順序:當前所在的位置向上一層一層查詢
#內建名稱空間
#全域性名稱空間
#區域性名稱空間

#如果當前在區域性名稱空間:
#區域性名稱空間->全域性名稱空間->內建名稱空間

例項1:
#當尋找input的在區域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
input=333
def func():
input=444
print(input) # 區域性是不是存在input啊 可知:input=444
#所以你輸出的必然是input=444
func()

例項2
#當尋找input的在不在區域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
# 是不是應在去全局裡面找啊
input=333
def func():
print(input) # 區域性不存在input啊 可知:全域性input=333
#所以你輸出的必然是input=333
func()

# 例項3
#當尋找input的在不在區域性,也不在全域性時,根據順序 區域性名稱空間->全域性名稱空間->內建名稱空間
# 是不是應在去內建裡面找啊

def func():
print(input) # 區域性不存在input啊 全局裡也沒input
#所以你輸出的必然是input在內建函式裡面的input()函式!!!
func()

# 故輸出結果是:<built-in function input>



#如果當前在全域性名稱空間
#全域性名稱空間->內建名稱空間

# 原理同上
input=333
def func():
input=444
func()
print(input)#全域性名稱空間進行查詢

# 示範1
def func():
print(x)
x=111
func()

def func():
print(x)

func()
x=111
#示範2:名稱空間的關係 區域性名稱空間(省份) > 全域性名稱空間(國家) > 內建名稱空間(地球)
# 名稱空間的"巢狀"關係是以函式定義階段為準,與呼叫位置無關
x=1
def func():
print(x)

def foo():
x=222
func()
foo()

#示範3:函式巢狀定義
#這裡是為了講解 使用input進行賦值 正常情況不要這麼寫!!!

input=111
def f1():
input=222
def f2():
input=333
print(input)
f2()
f1()




# 示範4
x=111
def func():
print(x)
x=222
func()


# 名字的查詢順序是從定義階段為準的 然後進行每層查詢的 (區域性名稱空間->全域性名稱空間->內建名稱空間)
但是在分析的時候要從定義階段為基準進行每層分析.,

"""
"""
2、作用域-->作用範圍
#全域性作用域:內建名稱空間、全域性名稱空間
特點:
1,全域性存活
2,全域性有效:被所有函式共享
# # 自定義函式不能相互找(除非相互巢狀)
def foo():
x=111
print(x)
def bar():
y=222
print(y)
foo()
bar()

#區域性作用域
特點:
1,臨時存活
2,區域性有效:只在自己的函式(區域性名稱空間)內有效
def foo(x):
def f1():
def f2():
print(x)



# 多個名稱空間為了方便定義有一個方法:LEGB(區域性名稱空間)(!!!!!!!瞭解內容)

# 三,global與 nonLocal
# global:
# 例項1 x=111 與x=222 無關,因為一個是全域性 一個是區域性
x=111
def func():
x=222
func()
print(x)

#例項2 如果在區域性想要修改全域性的名字對應的值,需要用global(要求是不可變型別)
x=111
def func():
global x #申明x為全域性名字 x=222為-到了全域性名稱空間會把111改成222
x=222
func()
print(x)


# 例項3 (可變型別)
l=[111,222]
def func():
l.append()
func()
print(l)


# nonlocal(瞭解):修改函式外層函式包含的名字對應的值(不可變型別)
# 例項1
def f1():
x=11
def f2():
global x
x=22
f2()
print("f1內的x:",x)
f1()

# 例項2

def f1():
x=11
def f2():
nonlocal x #若x=11不存在的 則報錯 若存在 則就改變外層x=11的值
x=22
f2()
print("f1內的x:",x)
f1()

"""