1. 程式人生 > >python入門基礎-三元表達式、命名空間、作用域、函數名本質、閉包

python入門基礎-三元表達式、命名空間、作用域、函數名本質、閉包

作用範圍 本質 代碼 順序 pre 區別 引用 一個 擁有

1.三元表達式(三目運算式)

#1 三元表達式(三目運算法)
#格式為: 為真時的結果 if 判定條件 else 為假時的結果
#另外三元表達式只適合較為簡潔的條件判定,較為復雜的判定建議不要用這種方式寫代碼,因為比較讓他人難以理解。

a = 10
b = 15

compare = a if  a > b else b    #誰大返回誰
print(compare)

2.命名空間(namespace)

#2 命名空間(namespace)
#命名空間是名稱和對象的印象,也可以將命名空間理解成一個字典,例如定義變量的時候,變量名名就是對應字典的key,而後面的賦值內容就是字典的value,再舉例說函數也是一樣,函數名就是字典的key,函數體就是字典的value;
#各個命名空間是獨立的,沒有任何關系的,所以一個命名空間中不能存在重名,但不同的命名空間可以重名並且沒有影響。 #在python當中命名空間分為內置空間、全局空間、局部空間三種。 #(1)python解釋器擁有自己內置空間,內置的函數在解釋器啟動時就被加載到內存中,任何模塊都可以訪問它,它存放著函數和異常。 #(2)每個模塊擁有它自已的命名空間,叫做全局命名空間,它記錄了模塊的變量,包括函數、類、其它導入的模塊、模塊級的變量和常量。 #(3)每個函數都有著自已的命名空間,叫做局部命名空間,它記錄了函數的變量,包括函數的參數和局部定義的變量。

3.命名空間查找順序

#3 命名空間查找順序
# 假設查找當前命名空間中的“s”變量。 # (1)局部命名空間:首先在局部命名空間中查找,如果沒有發現繼續去上層全局命名空間查找,如果再沒有繼續向上層內置命名空間查找,如果再沒有python會返回錯誤。 # (2)全局命名空間:首先在全局命名空間中查找,如果沒有發現繼續去上層內置命名空間查找,如果再沒有python會返回錯誤。 # (3)內置命名空間:如果在內置命名空間差找不到,直接返回錯誤。 #1)局部命名空間內調用全局命名空間的變量: a = 10 def my(): print(a) #可以成功打印出來10 my() #如果換成這樣就不能調用了: a = 10 def
my(): a += 1 #對於不可變類型在局部命名空間中可以查看,但不能直接去修改。 #錯誤:UnboundLocalError: local variable ‘a‘ referenced before assignment print(a) #可以成功打印出來10 my() #在全局命名空間調用內置命名空間的變量: x = 10 def my(x): # x = 15 print(x) # x =15 my(15) print(x) # x = 10,全局命名空間只會在當前或上級內置命名空間中查找x,不會去局部命名空間中查找x

4.作用域

#4 作用域
#作用域就是作用範圍,按照生效範圍可以分為全局作用域和局部作用域兩種。
#(1)全局作用域:包含內置命名空間和全局命名空間,在整個文件中任意位置可以被引用,並且全局有效。
#(2)局部作用域:局部命名空間,只能在局部範圍內有效。

5.globals和locals的區別

# 5 globals和locals的區別
#globals方法
#globals永遠打印全局的名字
def a():
    print(globals())    #局部命名空間中的輸出結果和全局命名空間中的輸出結果一樣

a()
print(globals())

#locals方法
#輸出什麽,根據locals所在位置決定。
def func():
    a = 10
    b = 12
    print(locals()) #打印的信息時局部命名空間的變量信息

func()
print(locals()) #打印的信息和globals一樣


#global 關鍵字
#如果在局部命名空間中需要修改全局命名空間的變量值,需要在其之前用global聲明即可,其後面的操作將對全局變量有效。

a = 12
def func():
    global a    #對變量a進行全局聲明,之後的操作將對全局的變量有效
    a = 25
    print(a)    # a = 25 對全局變量有效

func()
print(a)    # a = 25

6.函數的嵌套和作用域

#6 函數的嵌套和作用域鏈
#(1)函數的嵌套調用
def my_compare1(a,b):       #順序1
    return a if a > b else b    #順序8    #順序10

def my_compare2(a,b,c):     #順序2
    c1 = my_compare1(a,b)   #順序7
    return my_compare1(c,c1)    #順序9

a = 10      #順序3
b = 20      #順序4
c = 15      #順序5
print(my_compare2(a,b,c))       #順序6    #順序11 打印函數的返回值

#(2)函數的嵌套定義
def f1():       #順序1
    print(in f1)      #順序3
    def f2():       #順序4
        print(in f2)      #順序6
    f2()            #順序5
f1()        #順序2

#(3)函數的作用域鏈
#one

def f1():
    a = 1
    def f2():
        def f3():
            print(a)    #打印出的結果是 1 ,因為現在f3屬於子局部命名空間,存在父局部命名空間,如果當前子局部域名空間沒有,就會向上查找變量a,直至到內置命名空間。
        f3()
    f2()

f1()

#two

def f1():
    a = 1
    def f2():
        a = 2
    f2()
    print(a in f1 : ,a)   #此處的變量a,打印出來的是1,因為print和f2函數命名所處f1函數體中,而f2函數體中的a = 2 所處空間是print所在空間的子局部空間,所以print 打印 a的時候不會向下查找。
f1()


#(4)nonlocal關鍵字
#nonlocal 只能用於局部變量 找上層中離當前函數最近一層的局部變量
#聲明了nonlocal的內部函數的變量修改會影響到 離當前函數最近一層的局部變量
a = 10
def f1():
    a = 1
    def f2():
        a = 2
        def f3():
            nonlocal a  #對變量聲明nonlocal之後,後面對變量a的操作只會對上一層的局部變量有影響。
            a = 2 + 1
        f3()
        print(a in f2:,a)
    f2()
    print(a in f1 : ,a)

f1()
print(a)

7.函數名的本質

#7 函數名的本質
#函數名本質上就是函數的內存地址
#(1)可以被引用
def func():
    print(hello word!)
fun = func
fun()   #fun()和func()調用函數體之後,打印的信息完全一致
func()

#(2)可以被當作容器類的元素
def f1():
    print(f1)
def f2():
    print(f2)
def f3():
    print(f3)

l = [f1,f2,f3]
d = {f1:f1,f2:f2,f3:f3}
#調用
l[0]()  #調用f1函數體的內容
d[f2]()   #調用f2函數體的內容

#(3)可以當做函數的參數或返回值
#當參數
def func1():
    print(abc)

def func2(func1):
    func1()         #調用func1函數
    print(def)

func2(func1)    #將func1函數名當做參數傳遞給func2函數

#當返回值
def func1():
    print(abc)

def func2():
    print(def)
    return func1    #將func1函數名當做地址返回

a = func2() #將func1函數的內存地址復制給變量a
a() #調用func1函數

8.閉包

#8 閉包函數
#閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在
# ,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。(看起來相當難以理解)

#對於上面的解釋,我總結閉包在嵌套函數的環境中,內部函數調用外部函數的變量,並且外部函數的變量一直存在,下面舉個例子看看。
def func():
    a = 0
    print(輸出外部函數的變量:,a)
    def f1():
        print(內部函數輸出變量:,a)
    return  f1

f = func()
f()         #第一次調用會打印出來“輸出外部函數的變量: 0” 和“內部函數輸出變量: 0”
f()         #再次調用會打印出來“內部函數輸出變量: 0”,包括後面無論幾次調用,打印的結果都是這種,不會出現上面的情況,這就是閉包的方式之一

#判斷閉包函數的方法__closure__
#輸出的__closure__有cell元素 :是閉包函數
def func():
    name = eva
    def inner():
        print(name)
    print(inner.__closure__)    #打印結果:(<cell at 0x00000221EB0A0B58: str object at 0x00000221EB8438F0>,)
    return inner

f = func()
f()

#輸出的__closure__為None :不是閉包函數
name = egon
def func2():
    def inner():
        print(name)
    print(inner.__closure__)    #因為外部函數體(局部空間)內不存在變量,所以打印結果:None
    return inner

f2 = func2()
f2()

python入門基礎-三元表達式、命名空間、作用域、函數名本質、閉包