1. 程式人生 > >python學習 day10打卡 函式的進階

python學習 day10打卡 函式的進階

本節主要內容:

1.函式引數--動態引數

2.名稱空間,區域性名稱空間,全域性名稱空間,作用域,載入順序.

3.函式的巢狀

4.gloabal,nonlocal關鍵字

 

一.函式引數--動態傳參

形參的第三種:動態引數

動態引數分成兩種:

1.動態接收位置引數

def chi(*food):    
    print("我要吃", food) 

chi("⼤米飯", "小米飯") 

結果: 
我要吃 ('⼤米飯', '小米飯')    # 多個引數傳遞進去. 收到的內容是元組tuple
 

 

 動態引數接收引數的時候要注意:動態引數必須在位置引數後面

def chi(*food, a, b):    
    print("我要吃", food, a, b)

chi("⼤米飯", "小米飯", "⻩瓜", "茄子")

 這時程式執行會報錯.因為前面傳遞進去的所有位置引數都被*food接收了.a和b永遠接收不到引數

所以必須改成以下程式碼:

def chi(*food, a, b):    
  print("我要吃", food, a, b) 
chi("⼤米飯", "小米飯", a="黃瓜", b="茄子")   # 必須用關鍵字引數來指定

 這個時候a和b就有值了,但是這樣寫呢位置引數就不能用了,所以我們要先寫位置引數,然後再用動態引數

def chi(a, b, *food):    
    print("我要吃", a, b, food) 
chi("⼤米飯", "小米飯", "饅頭", "麵條")   # 前兩個引數用位置引數來接收, 後面的引數用 動態引數接收

 

那麼預設值引數呢?

def chi(a, b, c='饅頭', *food):    
    print(a, b, c, food) 

chi("⾹蕉", "菠蘿")  # 香蕉 菠蘿 饅頭 (). 預設值生效 
chi("⾹蕉", "菠蘿", "葫蘆娃")  # 香蕉 菠蘿 葫蘆娃 ()    預設值不生效 
chi("
香蕉", "菠蘿", "葫蘆娃", "口罩") # 香蕉 菠蘿 葫蘆娃 ('口罩',) 預設值不生效

 

我們發現預設值引數寫在動態引數前面.預設值只有一種情況可能會生效.

def chi(a, b, *food, c="娃哈哈"):    
    print(a, b, food, c) 

chi("香蕉", "菠蘿")  # 香蕉 菠蘿 () 娃哈哈   預設值生效 
chi("⾹蕉", "菠蘿", "葫蘆娃")  # ⾹蕉 菠蘿 ('葫蘆娃',) 娃哈哈    預設值生效 
chi("香蕉", "菠蘿", "葫蘆娃", "口罩")    # ⾹蕉 菠蘿 ('葫蘆娃', '口罩') 娃哈哈  預設值生效

 

這個時候我們發現所有的預設值都生效了.這個時候如果不給出關鍵字傳參,那麼你的預設值是永遠生效的.

順序:位置引數,動態引數*,預設值引數

 

2.動態接收關鍵字引數

在python中可以動態的位置引數,但是*這種情況只能接受位置引數無法接收關鍵字引數.

在python中使用**來接收動態關鍵字引數

def func(**kwargs):    
    print(kwargs) 

func(a=1, b=2, c=3) 
func(a=1, b=2) 

結果:
{'a': 1, 'b': 2, 'c': 3} 
{'a': 1, 'b': 2}

 這個時候接收的是一個dict

順序的問題,在函式呼叫的時候,如果先給出關鍵字引數,則整個引數列表會報錯.

def func(a, b, c, d):    
    print(a, b, c, d)

# 關鍵字引數必須在位置引數後面, 否則引數會混亂 
func(1, 2, c=3, 4)

 

所以關鍵字引數必須在位置引數後面.由於實參是這個順序.所以形參接收的時候也是整個順序,也就是說位置引數必須在關鍵字引數前面.動態接收關鍵字引數也要在後面

 最終順序(*):

位置引數>*args>預設值引數>**kwagrs


這四種引數可以任意的進行使用.

如果想接收所有的引數:

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

func("麻花藤","馬暈",wtf="胡辣湯")

 

動態引數的另一種傳參方式:

def fun(*args):    
    print(args)

lst = [1, 4, 7] 
fun(lst[0], lst[1], lst[2]) 
fun(*lst)   # 可以使用*把⼀個列表按順序打散 

s = "臣妾做不到" 
fun(*s)     # 字元串也可以打散, (可迭代物件)

 

在實參位置上給一個序列,列表,可迭代物件前面加個*表示把這個序列按順序打散.

在形參的位置上的*表示把接收到的引數組合成一個元組

如果是一個字典,那麼也可以打散.不過需要兩個*

def fun(**kwargs):    
    print(kwargs) 
dic = {'a':1, 'b':2} 
fun(**dic)

 函式的註釋:

def chi(food, drink):   
    """
    這裡是函式的註釋,先寫一下當前這個函式是幹什麼的,比如我這個函式就是一個吃
    :param food :引數是什麼意思
    :param drink:引數drink是什麼意思
    :return:返回的什麼東東
    """
    print(food,drink)
    return "very good"

 

二.名稱空間

在python直譯器開始執行之後,就會在記憶體中開闢一個空間,每當遇到一個變數的時候,就把變數名和值之間的關係記錄下來,但是當遇到函式定義的時候,

直譯器只是把函式名讀入記憶體,表示這個函式存在了,至於函式內部的變數和邏輯,直譯器是不關心的.也就是說一開始的時候函式只是健在進來了,僅此而已,

只有當函式被呼叫和訪問的時候,直譯器才會根據函式內部的宣告的變數來進行開闢變數的內部空間.隨著函式執行完畢,這些函式內部變數佔用的空間也會

隨著函式執行完畢而被清空

def fun():   
    a = 10    
    print(a) 
fun() 
print(a)    # a不存在了已經..

 

我們給存放名字和值的關係的空間起了一個名字叫:名稱空間,我們的變數在儲存的時候就是儲存在這片空間中的

名稱空間的分類:

1.全域性名稱空間-->我們直接在py檔案中,函式外宣告的變都屬於全域性名稱空間

2.區域性名稱空間-->存放函式中宣告的變數會放在區域性名稱空間

3.內建名稱空間-->存放python直譯器為我們提供的名字,list,tuple,str,int這些都是內建名稱空間

 

載入順序:

1.內建名稱空間

2.全域性名稱空間

3.區域性名稱空間(函式被執行的時候)

取值順序:

1.區域性名稱空間

2.全域性名稱空間

3.內建名稱空間

作用域:作用域就是作用範圍,按照生效的範圍來看分為:全域性作用域和區域性作用域

全域性作用域:包含內建名稱空間和全域性名稱空間.在整個檔案的任何位置都可以使用(遵循從上到下逐行執行).

區域性作用域: 在函式內部可以使用

作用域名稱空間:

1.全域性作用域: 全域性名稱空間+內建名稱空間

2.區域性作用域: 區域性名稱空間

我們可以通過globals()函式來檢視全域性作用域中的內容,也可以通過locals()來檢視區域性作用域中的變數和函式資訊.

 

def chi():
    p = 30
    print(locals()) # {'p': 30}   locals()可以檢視區域性作用域中的內容
    print(p)
# chi()
print(locals()) # 檢視當前作用域中的名字
print(globals())

 

 

三.函式的巢狀

1.只要遇見了()就是函式的呼叫.如果沒有()就不是函式的呼叫

2.函式的執行順序

# 一個套一個
def outer():
    print("我是outer")
    # 在函式內部宣告的函式, 只能在函式內部訪問
    def inner():
        print('我是inner')
    inner()
    print("我是outer_end")

outer()

 

def fun2():
    print(222)
    def fun3():
        print(666)
    print(444)
    fun3()
    print(888)
print(33)
fun2()
print(555)

# 33 222 444 666 888 555

 

四.關鍵字global和nonlocal

  首先我們寫下這樣一個程式碼,首先在全域性宣告一個變數,然後再區域性呼叫這個變數,並改變這個變數的值

a = 10
def func():
    global a  # 直接從全域性把變數引入進來
    a = 20


    # a = 20 # 並沒有改變全域性變數,   建立了一個自己的變數
    # 全域性變數在區域性, 可以用, 但是, 不能改
    # a = a + 10
    print(a)

func()
print(a)

 

global表示.不再使用區域性作用域中的內容了.而改用全域性作用域中的變數

nonlocal表示在區域性作用域中,呼叫父級名稱空間中的變數.

def outer():
    a = 10
    def inner():
        nonlocal a
        a = 20
        print(a)
    print(a)  # 10
    inner()   # 20
    print(a)  # 20
outer()

 再看如果嵌套了很多層,會是一種什麼效果:

a = 1
def fun_1():
    a = 2
    def fun_2():
        nonlocal a
        a = 3
        def fun_3():
            a = 4
            print(a)
        print(a)
        fun_3()
        print(a)
    print(a)
    fun_2()
    print(a)
print(a)
fun_1()
print(a)

# 1234331