函數的進階

来源:https://www.cnblogs.com/y0413/archive/2018/11/01/9892039.html
-Advertisement-
Play Games

本節主要內容: 1. 函數參數--動態傳參 2. 名稱空間, 局部名稱空間, 全局名稱空間, 作⽤域, 載入順序. 3. 函數的嵌套 4. gloabal, nonlocal關鍵字 ⼀. 函數參數--動態傳參 之前我們說過了傳參, 如果我們需要給⼀個函數傳參, ⽽參數⼜是不確定的. 或者我給⼀個 函 ...


本節主要內容:

1. 函數參數--動態傳參

2. 名稱空間, 局部名稱空間, 全局名稱空間, 作⽤域, 載入順序.

3. 函數的嵌套

4. gloabal, nonlocal關鍵字

⼀. 函數參數--動態傳參

之前我們說過了傳參, 如果我們需要給⼀個函數傳參, ⽽參數⼜是不確定的. 或者我給⼀個 函數傳很多參數, 我的形參就要寫很多, 很⿇煩, 怎麼辦呢. 我們可以考慮使⽤動態參數.

形參的第三種: 動態參數

動態參數分成兩種:

1. 動態接收位置參數

 ⾸先我們先回顧⼀下位置參數, 位置參數, 按照位置進⾏傳參

def chi(quality_food, junk_food):
    print("我要吃", quality_food, junk_food)
chi("⼤⽶飯", "⼩⽶飯")  # "⼤⽶飯"傳遞給quality_food  "⼩⽶飯"傳遞給junk_food
按照位置傳

現在問題來了. 我想吃任意的食物. 數量是任意的, 食物也是任意的. 這時我們就要⽤到 動態參數了. 在參數位置編寫*表⽰接收任意內容

def chi(*food):
    print("我要吃", food)
chi("⼤⽶飯", "⼩⽶飯")
結果:
我要吃 ('⼤⽶飯', '⼩⽶飯') # 多個參數傳遞進去. 收到的內容是元組tuple

動態接收參數的時候要註意: 動態參數必須在位置參數後⾯

def chi(*food, a, b):
    print("我要吃", food, a, b)
chi("⼤⽶飯", "⼩⽶飯", "⻩⽠", "茄⼦")

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

Traceback (most recent call last):
    File "/Users/sylar/PycharmProjects/oldboy/fun.py", line 95, in <module>
    chi("⼤⽶飯", "⼩⽶飯", "⻩⽠", "茄⼦")
TypeError: chi() missing 2 required keyword-only arguments: 'a' and '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 > 預設值參數 > **kwargs

       這四種參數可以任意的進⾏使⽤.

   如果想接收所有的參數:

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 :param food: 參數food是什麼意思
 :param :param drink: 參數drink是什麼意思
 :return :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. 內置命名空間

a = 10
def func():
    a = 20
    print(a)
func() # 20

作⽤域: 作⽤域就是作⽤範圍, 按照⽣效範圍來看分為 全局作⽤域和局部作⽤域

全局作⽤域: 包含內置命名空間和全局命名空間. 在整個⽂件的任何位置都可以使⽤(遵循 從上到下逐⾏執⾏). 局部作⽤域: 在函數內部可以使⽤.

作⽤域命名空間:

1. 全局作⽤域: 全局命名空間 + 內置命名空間

2. 局部作⽤域: 局部命名空間

我們可以通過globals()函數來查看全局作⽤域中的內容, 也可以通過locals()來查看局部作 ⽤域中的變數和函數信息

a = 10
def func():
    a = 40
    b = 20
    def abc():
    print("哈哈")
    print(a, b) # 這⾥使⽤的是局部作⽤域
    print(globals()) # 列印全局作⽤域中的內容
    print(locals()) # 列印局部作⽤域中的內容
func()

三. 函數的嵌套

1. 只要遇⻅了()就是函數的調⽤. 如果沒有()就不是函數的調⽤

2. 函數的執⾏順序

def fun1():
    print(111)
 
def fun2():
    print(222)
    fun1()

fun2()
print(111)
# 函數的嵌套
def fun2():
    print(222)
    def fun3():
      print(666)
    print(444)
    fun3()
    print(888)
print(33)
fun2()
print(555)

四. 關鍵字global和nonlocal

  ⾸先我們寫這樣⼀個代碼, ⾸先在全局聲明⼀個變數, 然後再局部調⽤這個變數, 並改變這 個變數的值

 

 

a = 100
def func():
    global a # 加了個global表示不再局部創建這個變數了. ⽽是直接使⽤全局的a
    a = 28
    print(a)
func()
print(a)

 

      global表⽰. 不再使⽤局部作⽤域中的內容了. ⽽改⽤全局作⽤域中的變數

lst = ["麻花藤", "劉嘉玲", "詹姆斯"]
def func():
    lst.append("⻢云云") # 對於可變數據類型可以直接進⾏訪問. 但是不能改地址. 說⽩
了. 不能賦值
    print(lst)
func()
print(lst)

nonlocal 表⽰在局部作⽤域中, 調⽤⽗級命名空間中的變數.

a = 10
def func1():
    a = 20
    def func2():
    nonlocal a
    a = 30
    print(a)
    func2()
    print(a)
func1()
結果:
加了nonlocal
30
30
不加nonlocal
30
20

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

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)

這樣的程式如果能分析明⽩. 那麼作⽤域, global, nonlocal就沒問題了

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 由於筆者在自己設計CRC模塊時遇到很多問題,在網上並未找到一篇具有實際指導意義的文章,在經過多次模擬修改再模擬之後得到了正確的結果,故願意在本文中為大家提供整個設計流程供大家快速完成設計。本文章主要針對具體的實際應用給出一套親測可行的實現辦法,給出設計代碼並提供模擬結果,供各位參考。 一.CRC概述 ...
  • 多線程 thread_local 類型 thread_local變數是C++ 11新引入的一種存儲類型。 thread_local關鍵字修飾的變數具有線程周期(thread duration), 這些變數(或者說對象)線上程開始的時候被生成(allocated), 線上程結束的時候被銷毀(deall ...
  • 一、列表推導式 寫點:[結果 for 變數 in 可迭代對象 if 判斷] 二、字典推導式 寫法:[結果 for 變數 in 可迭代對象 if 判斷] 三、集合推導式 寫法:[結果 for 變數 in 可迭代對象 if 判斷] 結論: 推導式比較耗記憶體。一次載入。而生成器表達式幾乎不占用記憶體。使用的 ...
  • 一.概述 當你在嘗試一門新的語言時,可能不會過於關註程式出錯的問題, 但當真的去創造可用的代碼時,就不能再忽視代碼中的可能產生的錯誤和異常了。 鑒於各種各樣的原因,人們往往低估了語言對錯誤處理支持程度的重要性。 事實會表明,Scala 能夠很優雅的處理此類問題, 這一部分,我會介紹 Scala 基於 ...
  • 證明: ...
  • url映射的作用 根據Django的MTV模式,url的映射是根據用戶輸入或傳送而來的url路徑,來進行區分去執行相應的view函數來響應用戶的操作。 url映射的方式 Django項目的創建後,會自動創建和你項目名稱相同的全局文件包,urls.py就在其中。 urlpatterns = [ pat ...
  • javaServlet的構建,servlet,java前端和後端的通信 ...
  • "State of the Lambda" 這篇主要講 Labmbda 的背景和用法 譯文: "深入理解Java 8 Lambda(語言篇——lambda,方法引用,目標類型和預設方法)" "State of the Lambda: Libraries Edition" 這篇主要講 Stream 操 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...