python參數和作用域,python中變數作用域

本文目錄一覽:

Python其實很簡單 第十二章 函數與變數的作用域

在前面已經多次提到函數這個概念,之所以沒有解釋什麼是函數,是因為程序中的函數和數學中的函數差不多,如input()、range()等都是函數,這些都是Python的標準函數,直接使用就可以了。根據需要,用戶也可以自定義函數。

12.1 函數

函數的結構:

def 函數名(參數):

函數體

return 返回值

例如:數學中的函數f(x)=2x+5在Python中可以定義如下:

def f(x):

y=2*x+5

return(y)

如果x取值為3,可以使用如下語句調用函數:

f(3)

下面給出完整的程序代碼:

def f(x):

y=2*x+5

return(y)

res=f(3)

print(res)

運行結果:11

如上例中的x是函數f(x)的參數,有時也被稱為形式參數(簡稱形參),在函數被調用時,x被具體的值3替換y就是函數的返回值,這個值3也被稱為實際參數(簡稱實參)。

上例中的y是函數f(x)的返回值。並不是所有的函數都有參數和返回值。如下面的函數:

def func():

print(‘此為無參數傳遞、無返回值的函數’)

func()

輸出結果:此為無參數傳遞、無返回值的函數

可以看出,該函數func()無參數,故調用時不用賦給參數值。

函數也可以有多個參數,如f(x,y)=x²+y²,可用Python語言定義如下:

def f(x,y):

z=x**2+y**2

return z

print(f(2,3)) #調用函數f(x,y)

輸出結果:13

也可以通過直接給參數列表中的參數賦值的方法,為參數添加默認值,如果用戶賦予參數值,則按照用戶賦值執行,否則使用默認值。例如:

def f(x,y=3):

z=x**2+y**2

return z

若調用時參數列表為(2,1),即x賦值為2,y賦值為1:

print(f(2,1))

輸出結果為:5

若調用時參數列表為(2),即x賦值為2,y賦值省缺,則y使用默認值:

print(f(2))

輸出結果為:13

回調函數,又稱函數回調,是將函數作為另一函數的參數。

例如:

def func(fun,m,n):

fun(m,n)

def f_add(m,n):

print(‘m+n=’,m+n)

def f_mult(m,n):

print(‘m*n=’,m*n)

func(f_add,2,3)

func(f_mult,2,3)

輸出結果:

m+n= 5

m*n= 6

在f_add(m,n)和f_mult(m,n)被定義前,func(fun,m,n)中的fun(m,n)就已經調用了這兩個函數,即「先調用後定義」,這也是回調函數的特點。

如果無法預知參數的個數,可以在參數前面加上*號,這種參數實際上對應元組類型。譬如,參會的人數事先不能確定,只能根據與會人員名單輸入:

def func(*names):

print(‘今天與會人員有:’)

for name in names:

print(name)

func(‘張小兵’,’陳曉梅’,’李大海’,’王長江’)

運行後,輸出結果為:

今天與會人員有:

張小兵

陳曉梅

李大海

王長江

參數為字典類型,需要在參數前面加上**號。

def func(**kwargs):

for i in kwargs:

print(i,kwargs[i])

func(a=’a1′,b=’b1′,c=’c1′)

輸出結果為:

a a1

b b1

c c1

一個有趣的實例:

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

print(x,y,z)

print(args)

print(kwargs)

func(‘a’,’b’,’c’,’Python’,’is easy’,py=’python’,j=’java’,ph=’php’)

輸出結果:

a b c # 前三個實參賦給前三個形參

(‘Python’, ‘is easy’) # *args接收元組數據

{‘py’: ‘python’, ‘j’: ‘java’, ‘ph’: ‘php’} # **kwargs接收字典數據

12.2 變數的作用域

變數的作用域即變數的有效範圍,可分為全局變數和局部變數。

局部變數

在函數中定義的變數就是局部變數,局部變數的作用域僅限於函數內部使用。

全局變數

在主程序中定義的變數就是全局變數,但在函數中用關鍵字global修飾的變數也可以當做全局變數來使用。

全局變數的作用域是整個程序,也就是說,全局變數可以在整個程序中可以訪問。

下面通過實例去討論:

程序1:

a=1 # a為全局變數

def a_add():

print(‘a的初值:’,a) # 在函數中讀取a的值

a_add() # 調用函數a_add()

a+=1 # 主程序語句,a增加1

print(‘a現在的值是:’,a) # 主程序語句,讀取a的值

運行結果:

a的初值: 1

a現在的值是: 2

這個結果和我們想像的一樣,全局變數a既可以在主程序中讀取,也可以在子程序(函數)中讀取。

程序2:

a=1

def a_add():

a+=1

print(‘a的初值:’,a)

a_add()

print(‘a現在的值是:’,a)

運行程序1時出現如下錯誤提示:

UnboundLocalError: local variable ‘a’ referenced before assignment

意思是:局部變數’a’在賦值之前被引用。

從語法上來講,該程序沒有錯誤。首先定義了一個全局變數a並賦值為1,又定義了一個函數a_add(),函數內的語句a+=1就是出錯的根源,雖然我們的初衷是想讓全局變數a的值增加1,但從錯誤提示看,這個語句中的a並不是全局變數,而是局部變數。看來,在函數中讀取全局變數的值是沒有問題的(在程序1中已經得到了驗證),但要在函數中改變全局變數的值是不行的(在程序2的錯誤提示a+=1中的a 是局部變數,而非全局變數)。

怎樣解決這個問題?

程序3:

a=1

def a_add(x):

x+=1

return x

print(‘a的初值:’,a)

a=a_add(a)

print(‘a現在的值是:’,a)

運行結果:

a的初值: 1

a現在的值是: 2

結果的確是正確的,但在函數a_add(x)中沒有調用變數a(沒有出現變數a)。

程序4:

a=1

def a_add(a):

a+=1

return a

print(‘a的初值:’,a)

a=a_add(a)

print(‘a現在的值是:’,a)

運行結果:

a的初值: 1

a現在的值是: 2

對比程序4和程序3不難發現,其實程序4隻是簡單的把函數的參數x變成了a,這個a的實質和程序3中的x還是一樣的。這進一步證實,函數中的a是局部變數,與主程序的全局變數a有著本質的區別。

程序5:

a=1

def a_add():

global a

a+=1

print(‘a的初值:’,a)

a_add()

print(‘a現在的值是:’,a)

運行結果:

a的初值: 1

a現在的值是: 2

程序5和程序2相比較,僅僅是在函數中添加了一個定義「global a」,此時的局部變數a就可以當做全局變數使用,由於它和全局變數a同名,自然也就不用區分a究竟是全局變數還是局部變數了,在主程序和該函數內都可以訪問、修改變數a的值了。

雖然使用global可使變數使用起來非常方便,但也容易引起混淆,故在使用過程中還是謹慎為好。

12.3 函數的遞歸與嵌套

遞歸,就是函數調用它自身。遞歸必須設置停止條件,否則函數將無法終止,形成死循環。

以計算階乘為例:

def func(n):

if n==1:

return 1

else:

return n*func(n-1) #func( )調用func( )

print(func(5))

運行結果為:120

嵌套,指在函數中調用另外的函數。這是程序中常見的一種結構,在此不再贅述。

匿名函數

Python中可以在參數前加上關鍵字lambda定義一個匿名函數,這樣的函數一般都屬於「一次性」的。

例如:

程序1:這是一個常規的函數定義和調用。

def f_add(x,y):

return x+y

print(f_add(2,3))

輸出結果:5

程序2:使用lambda定義匿名函數。

f_add=lambda x,y:x+y

print(f_add(2,3))

輸出結果:5

從上面的代碼可以看出,使用lambda僅僅減少了一行代碼。f_add=lambda x,y:x+y中的f_add不是變數名,而是函數名。程序1和程序2的print( )語句中的參數都是一樣的——調用函數f_add( )。所以,匿名函數並沒有太多的優點。

Python語言中作用域怎麼理解?

命名空間 是從命名到對象的映射。當前命名空間主要是通過 Python 字典實現的,不過通常不關心具體的實現方式(除非出於性能考慮),以後也有可能會改變其實現方式。以下有一些命名空間的例子:內置命名(像 abs() 這樣的函數,以及內置異常名)集,模塊中的全局命名,函數調用中的局部命名。某種意義上講對象的屬性集也是一個命名空間。關於命名空間需要了解的一件很重要的事就是不同命名空間中的命名沒有任何聯繫,例如兩個不同的模塊可能都會定義一個名為 maximize 的函數而不會發生混淆-用戶必須以模塊名為前綴來引用它們。

順便提一句,我稱 Python 中任何一個「.」之後的命名為 屬性 --例如,表達式 z.real 中的 real 是對象 z 的一個屬性。嚴格來講,從模塊中引用命名是引用屬性:表達式 modname.funcname 中,modname 是一個模塊對象,funcname 是它的一個屬性。因此,模塊的屬性和模塊中的全局命名有直接的映射關係:它們共享同一命名空間![1]

屬性可以是只讀過或寫的。後一種情況下,可以對屬性賦值。你可以這樣做: modname.the_answer = 42 。可寫的屬性也可以用 del 語句刪除。例如: del modname.the_answer 會從 modname 對象中刪除 the_answer 屬性。

不同的命名空間在不同的時刻創建,有不同的生存期。包含內置命名的命名空間在 Python 解釋器啟動時創建,會一直保留,不被刪除。模塊的全局命名空間在模塊定義被讀入時創建,通常,模塊命名空間也會一直保存到解釋器退出。由解釋器在最高層調用執行的語句,不管它是從腳本文件中讀入還是來自互動式輸入,都是 __main__ 模塊的一部分,所以它們也擁有自己的命名空間(內置命名也同樣被包含在一個模塊中,它被稱作 builtins )。

當調用函數時,就會為它創建一個局部命名空間,並且在函數返回或拋出一個並沒有在函數內部處理的異常時被刪除。(實際上,用遺忘來形容到底發生了什麼更為貼切。)當然,每個遞歸調用都有自己的局部命名空間。

作用域 就是一個 Python 程序可以直接訪問命名空間的正文區域。這裡的直接訪問意思是一個對名稱的錯誤引用會嘗試在命名空間內查找。儘管作用域是靜態定義,在使用時他們都是動態的。每次執行時,至少有三個命名空間可以直接訪問的作用域嵌套在一起:

PYTHON 的變數作用域與內存分配

原理:python中任何變數都是對象,所以參數只支持引用傳遞方式。即通過名字綁定的機制,把實際參數的值和形式參數的名稱綁定在一起,形式參數和實際參數指向內存中的同一個存儲空間。

回答問題2:

每一次給變數賦值就是把這個名稱的值在一個新內存中存儲

你print

(id

(a))

會發現每一次f(x),a的內存地址都是新的。所以你的問題二中L=[4,3]

與之前的L[]不是同一個名稱,所以append上a就是[4,3,3](簡明點就是L=[4,3]與L=[1,2]是兩不同名的玩意)

討論問題1:

在你的程序中a=1,a=2,a=5是int對象的三個實例,所以佔用的是三段不同的內存,自然在程序執行完收回內存的時候才會被清理;而L是通過列表的append方法進行變化時,print

(f(1))

print

(f(2))

print

(f(5))是對對一個實例進行操作的,所以內存地址不變;

同理print

(f(3,[4,3]))直接給L賦值時,由於

是一個新的列表實例了,內存位置自然變化。

產生以上的問題的根本原因就是python的精髓:萬物皆對象

(賦值的過程是對象的實例化)

看完自己的回答後:感覺真的很繞,不過我是儘力了,希望你能看懂,不明白的話,在追問里註明吧!

原創文章,作者:FWDY,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/135897.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
FWDY的頭像FWDY
上一篇 2024-10-04 00:15
下一篇 2024-10-04 00:15

相關推薦

  • Python周杰倫代碼用法介紹

    本文將從多個方面對Python周杰倫代碼進行詳細的闡述。 一、代碼介紹 from urllib.request import urlopen from bs4 import Bea…

    編程 2025-04-29
  • Python列表中負數的個數

    Python列表是一個有序的集合,可以存儲多個不同類型的元素。而負數是指小於0的整數。在Python列表中,我們想要找到負數的個數,可以通過以下幾個方面進行實現。 一、使用循環遍歷…

    編程 2025-04-29
  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • 如何查看Anaconda中Python路徑

    對Anaconda中Python路徑即conda環境的查看進行詳細的闡述。 一、使用命令行查看 1、在Windows系統中,可以使用命令提示符(cmd)或者Anaconda Pro…

    編程 2025-04-29
  • Python計算陽曆日期對應周幾

    本文介紹如何通過Python計算任意陽曆日期對應周幾。 一、獲取日期 獲取日期可以通過Python內置的模塊datetime實現,示例代碼如下: from datetime imp…

    編程 2025-04-29
  • int類型變數的細節與注意事項

    本文將從 int 類型變數的定義、聲明、初始化、範圍、運算和類型轉換等方面,對 int 類型變數進行詳細闡述和講解,幫助讀者更好地掌握和應用 int 變數。 一、定義與聲明 int…

    編程 2025-04-29
  • Python清華鏡像下載

    Python清華鏡像是一個高質量的Python開發資源鏡像站,提供了Python及其相關的開發工具、框架和文檔的下載服務。本文將從以下幾個方面對Python清華鏡像下載進行詳細的闡…

    編程 2025-04-29
  • python強行終止程序快捷鍵

    本文將從多個方面對python強行終止程序快捷鍵進行詳細闡述,並提供相應代碼示例。 一、Ctrl+C快捷鍵 Ctrl+C快捷鍵是在終端中經常用來強行終止運行的程序。當你在終端中運行…

    編程 2025-04-29
  • 蝴蝶優化演算法Python版

    蝴蝶優化演算法是一種基於仿生學的優化演算法,模仿自然界中的蝴蝶進行搜索。它可以應用於多個領域的優化問題,包括數學優化、工程問題、機器學習等。本文將從多個方面對蝴蝶優化演算法Python版…

    編程 2025-04-29
  • Python字典去重複工具

    使用Python語言編寫字典去重複工具,可幫助用戶快速去重複。 一、字典去重複工具的需求 在使用Python編寫程序時,我們經常需要處理數據文件,其中包含了大量的重複數據。為了方便…

    編程 2025-04-29

發表回復

登錄後才能評論