首頁 > 軟體

python3中的函數與引數及空值問題

2022-11-28 22:00:51

畫星星

程式2-7-7主要使用turtle.forward前進操作和turtle.left左轉操作在螢幕上畫星星。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-8.py
import turtle
turtle.color('Green','yellow')
while True:
    turtle.forward(200)
    turtle.left(150)
    print(turtle.pos())
    if abs(turtle.pos()) < 1:
        break
print('按確認鍵退出')
input()

程式2-7-7.py執行結果如下:

同時,程式2-7-7.py還輸出瞭如下所示的線轉角處(繪製一條直線後轉角繪製另一個直線,2條直線的交點)的位置資訊:
(200.00,0.00)
(26.79,100.00)
(126.79,-73.21)
(126.79,126.79)
(26.79,-46.41)
(200.00,53.59)
(0.00,53.59)
(173.21,-46.41)
(73.21,126.79)
(73.21,-73.21)
(173.21,100.00)
(0.00,-0.00)
按確認鍵退出
現對程式2-7-7.py分析如下:
1、該程式使用了以下幾個函數:
(1)forward函數前進200,用於繪製直線。
(2)left函數左轉150度,用於轉角,繪製另一條直線。
(3)turtle.pos()返回當前位置座標 (x,y) (座標為 Vec2D 向量類物件)。
(4) abs函數返回一個數的絕對值。 引數可以是整數、浮點數或任何實現了 abs() 的物件,當引數是一個複數時,返回它的模。在該程式中, abs的作用如下:
使用pos返回一個當前座標後,abs求該Vec2D座標到原點的距離(從原點出發的向量長度)。向量空間內的所有向量賦予非零的正長度或大小,在二維的歐氏幾何空間 R中定義歐氏範數,在該向量空間中,元素被畫成一個從原點出發的帶有箭頭的有向線段,每一個向量的有向線段(向量)的長度即為該向量的歐氏範數。
由於Vec2D是一個二維向量類,用來作為實現海龜繪圖的輔助類,也可以在海龜繪圖程式中使用,它派生自元組,因此向量也屬於元組。Vec2D主要提供以下運算 (a, b 為向量, k 為數值):
a + b 向量加法
a - b 向量減法
a * b 內積
k * a 和 a * k 與標量相乘
此外,Vec2D類還實現了 abs操作,如下面程式碼片斷所示(摘自Vec2D類原始碼)。

class Vec2D(tuple):
  ...
    def __abs__(self):
        return (self[0]**2 + self[1]**2)**0.5

2、程式2-7-7.py的執行過程如下:
(1)通過turtle.color(‘Green’,‘yellow’)函數設定顏色為綠色畫筆、黃色填充。
(2)建立迴圈體,迴圈體內容為:
首先,將海龜定位於原點。
然後,turtle.forward(200)前進200步,turtle.left(150)左轉150度,print(turtle.pos())列印出當前海龜位置。
最後,通過abs(turtle.pos())判斷當前向量(從原點到當前海龜位置的向量)的長度,如果長度<1,說明當前位置已經回到了起點(原點),就退出迴圈。如果長度>=1,則繼續迴圈。

空值None

Python None 物件,表示缺乏值、空值。
下面程式碼定義了x和y共2個變數,其中,x初始化值為0,而y設為了空值,x雖然為0,但仍然屬於有值狀態,而y屬於空值狀態。

>>>x=0
>>>y=None
>>>x==None
False
>>>y==None
True

函數與Lambda

一、函數定義

Python定義函數使用關鍵字 def,後跟函數名與括號內的形參列表。函數語句從下一行開始,並且必須縮排。
程式2-7-10-1.py定義了函數getSum,完成引數求和後返回 。
#!/usr/bin/env python3

# -*- coding: utf-8 -*-
#2-7-10-1.py
def getSum(x1,x2,x3,x4):
    y=x1+x2+x3+x4
    return y

print(getSum(11,22,33,44))
程式2-7-10-1.py執行結果如下:

110

程式2-7-10-1.py執行過程如下:
1、定義函數getSum,使用def關鍵字+函數名getSum的方式進行定義,引數為括號內的4個變數x1、x2、x3、x4。
函數的執行體為函數定義的下一行,共2行。
(1)第1行y=x1+x2+x3+x4,將4個引數之和賦值給變數y。其中,y是函數內區域性變數,而x1、x2、x3、x4為函數區域性變數。
(2)第2行return y,將y返回,return語句功能是是函數返回值,沒有 return 語句的函數也返回值,只不過這個值是 None。
2、呼叫getSum函數,並列印函數返回結果。

二、參照變數查詢

函數在執行時使用函數區域性變數符號表,所有函數變數賦值都存在區域性符號表中;參照變數時,其查詢順序為:首先,在區域性符號表裡查詢變數,然後,是外層函數區域性符號表,接著是全域性符號表,最後是內建名稱符號表。因此,雖然可以參照全域性變數和外層函數的變數,但是最好不要在函數內直接賦值(除非是 global 語句定義的全域性變數,或 nonlocal 語句定義的外層函數變數)。
程式2-7-10-2.py定義了函數getSum,完成引數求和後返回,與2-7-10-1.py基本相同,不同之處在於,在getSum函數體內出現了變數y,而在getSum函數體外也出現了變數y。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-2.py
y=9
def getSum(x1,x2,x3,x4):
    y=x1+x2+x3+x4
    return y

print(y)
print(getSum(11,22,33,44))
print(y)

程式2-7-10-2.py的執行結果為:

9
110
9

觀察程式2-7-10-2.py的執行結果,可發現,雖然,在getSum函數定義之前(之外),已經定義了變數y=9,隨後又在getSum函數體內將變數y的值改為了4個引數之和110,那麼在執行完getSum函數後,y的值會變為110,但在此處卻仍沒有變化,還是9。這是什麼原因呢?答案是:getSum函數體內的y存在於函數區域性變數符號表內,而getSum函數定義之外的y屬於全域性變數,2個y不屬於同一變數,因此,對getSum函數體內的y值進行的修改並不影響函數體之外定義的y的值。
那麼,如果一定要在getSum函數體內對函數體外定義的y進行修改,可按程式2-7-10-3.py所示的方法進行。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-3.py
y=9
def getSum(x1,x2,x3,x4):
     global y    
     y=x1+x2+x3+x4
     return y
print(y)
print(getSum(11,22,33,44))
print(y)

程式2-7-10-3.py的執行結果為:

9
110
110

程式2-7-10-3.py與程式2-7-10-2.py基本一樣,只是在函數體內通過global y,將y宣告為全域性變數,表示在函數體內使用的y就是全域性變數y,並非函數體區域性變數。
除了global還有一個語句nonlocal。nonlocal 語句會使得所列出的名稱指向之前在最近的包含作用域中繫結的除全域性變數以外的變數。 這種功能很重要,因為繫結的預設行為是先搜尋區域性名稱空間。 這個語句允許被封裝的程式碼重新系結區域性作用域以外且非全域性(模組)作用域當中的變數。
與 global 語句中列出的名稱不同,nonlocal 語句中列出的名稱必須指向之前存在於包含作用域之中的繫結。程式2-7-10-4.py演示了nonlocal的用法。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-4.py
def printY():
     y=9
     print(y)
     def getSum(x1,x2,x3,x4):
          nonlocal y    
          y=x1+x2+x3+x4
     getSum(100,2,3,4)
     print(y)
     
printY()

程式2-7-10-4.py的執行結果為:

9
109

對程式2-7-10-4.py分析如下:
1、該程式有2個函數體,這2個函數體是巢狀關係,即:getSum巢狀在printY內部。
2、對於getSum函數來說,在printY函數內部定義的y屬於區域性作用域以外且非全域性(模組)作用域當中的變數,且屬於最近的包含作用域(getSum包含在printY作用域內)中,getSum函數想存取printY函數的變數,需要宣告該變數為nonlocal變數。
3、在getSum函數體內對printY函數體定義的y值的修改是有效的。因此,程式執行後,第一次列印出y的值為初始值9,第二次修改後再列印出y的值為修改後的值109。

三、傳值呼叫函數

在呼叫函數時Python會將實際引數(實參)引入到被呼叫函數的區域性符號表中,因此,函數引數都是使用按值呼叫來傳遞的,所謂按值傳遞,會將值進行復制生成函數的區域性變數。當一個函數呼叫另外一個函數時,會為該呼叫建立一個新的區域性符號表。
但是,有一點要特別注意,Python中的物件分為可變物件與不可變物件,比如整數288屬於不可變物件,而列表[288,11]、[288,]就屬於可變物件。具體來說,strings、tuples和numbers是不可變物件,而list、dict等則是可變物件。
對於不可變物件的按值傳遞就是直接複製其值,而可變物件的按值傳遞是複製其參照,因為可變物件的值在Python內部實質表現為一個指向該物件的參照(記憶體地址,可理解為指標),順著這個參照才可在記憶體中找到該物件真正的值。程式2-7-10-5.py演示了引數傳遞的用法。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-5.py

def swapNum(x,y):
    temp=x
    x=y
    y=temp
def swapNums(nums):
    temp=nums[0]
    nums[0]=nums[1]
    nums[1]=temp

x=11
y=22

swapNum(x,y)
print(x,y)
n=[11,22]
swapNums(n)
print(n)

程式2-7-10-5.py的執行結果如下:

11 22
[22, 11]

對程式2-7-10-5.py分析如下:
1、該程式定義了2個函數swapNum和swapNums。
(1)swapNum函數想完成的功能是將傳入的2個引數值進行修改,完成互換,要能完成對呼叫swapNum的函數實際引數進行修改,而不是對函數區域性變數進行修改。
(2)swapNums函數想完成的功能是對傳入的列表進行修改,將其第0個元素和第1個元素進行互換,並保證修改效果影響到呼叫swapNums函數的變數。
但是,雖然都是傳值傳遞引數,但是swapNum函數的引數屬於不可變變數,swapNum函數體會複製它的2個引數,形成屬於自己的函數內部區域性引數,實質已經與呼叫swapNum的函數引數無關,修改是無效的;而swapNums函數的引數是列表,屬於可變變數,swapNums函數也會複製引數的值,但這個引數值是列表的地址(參照),那麼傳遞到swapNums函數體內部的引數就是該列表的參照,對該參照的修改直接影響到呼叫swapNums的函數,修改是有效的。
2、該程式定義整型變數x和y後,將其作為引數傳入swapNum,想完成x和y的互換, 這一操作是失敗的,無法成功,然後該程式又定義了列表n,將其作為 引數傳入swapNums,想完成第0個元素與第1個元素的互換,此操作是成功的。觀察程式2-7-10-5.py的執行結果可驗證這一結論。

四、函數物件

函數定義在當前符號表中把函數名與函數物件關聯在一起。直譯器把函數名指向的物件作為使用者自定義函數。還可以使用其他名稱指向同一個函數物件,並存取訪該函數。程式2-7-10-6.py演示了函數物件的用法。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-6.py

def swapNums(nums):
    temp=nums[0]
    nums[0]=nums[1]
    nums[1]=temp

swap=swapNums
n=[11,22]
print(n)
swap(n)
print(n)

程式2-7-10-6.py的執行結果如下:

[11, 22]
[22, 11]

程式2-7-10-6.py首先定義了swapNums函數及其函數體內容;然後,定義一個變數swap,將swapNums函數賦值給變數swap(Python中的變數屬於動態型別,物件的型別是可改變的),這樣,swap成為了一個函數物件;最後,程式直接使用swap作為函數名呼叫swapNums函數。

五、函數檔案

函數內的第一條語句可以是字串,其意義在於:該字串是DocString(檔案字串),利用檔案字串可以自動生成線上檔案或列印版檔案,還可以讓開發者在瀏覽程式碼時直接查閱檔案,Python 開發者最好可以養成在函數語句下一行中加入檔案字串的好習慣。程式2-7-10-7.py演示了函數檔案的用法。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-10-7.py
def swapNums(nums):
    """
    swapNums函數接受一個列表物件,
    完成將列表物件的2個元素互換位置的功能。
    """    
    temp=nums[0]
    nums[0]=nums[1]
    nums[1]=temp

print(swapNums.__doc__)
print("---------------------")
help(swapNums)

程式2-7-10-7.py的輸出結果如下:
swapNums函數接受一個列表物件,
完成將列表物件的2個元素互換位置的功能。

Help on function swapNums in module main:

swapNums(nums)
swapNums函數接受一個列表物件,
完成將列表物件的2個元素互換位置的功能。

分析程式2-7-10-7.py,該程式的執行過程如下:
1、定義swapNums函數,函數功能為:互換列表的2個元素。
(1)在函數體的第1行(即:def定義語句的下一行)開始用三引號標註了一段字串,該字串(是DocString(檔案字串),用於說明函數功能和用法等事項。在Python中單引號和雙引號都可以用來表示一個字串,而三單引號和三雙引號包圍的字串可保持原來的格式。
(2)函數體的第5行開始,是函數體的程式碼段,完成函數體的功能。
2、通過函數物件.doc(注意前後都是雙_)屬性,提取將DocString特性,該程式通過print(swapNums.doc)將函數swapNums的檔案字串列印在螢幕上。
3、通過help()呼叫提取DocString屬性並列印在螢幕上。該程式通過help(swapNums)將函數swapNums的檔案字串列印在螢幕上。
2.2.2 Lambda

myfun1= lambda a,b:math.sqrt(pow(a,2)+pow(b,2))
myfun2=lambda x:1 if (x%2==0) else 0
print(myfun1(12,19))
print(myfun2(193))

旋轉角度

程式2-7-11.py演示了以30度為步長逐漸增大角度進行旋轉,從0度開始直到360度為止。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-11.py
import turtle
turtle.color('Green','yellow')
lineLine=50
for i in range(0,361,30):
    turtle.home()
    turtle.left(i)  
    turtle.forward(lineLine+i)  
    turtle.write(f"{i}>[{turtle.position()[0]},n{turtle.position()[1]}]") 
turtle.home()
turtle.color('Black','red')
turtle.write(f"[{turtle.position()[0]},n{turtle.position()[1]}]") 

print('按確認鍵退出')
input()

程式2-7-11.py執行結果如下:

程式2-7-11.py的執行過程如下:
1、定義顏色為:畫筆綠色,填充黃色,設定直線初始長度lineLine為50。
2、for迴圈繪製直線,i為旋轉角度,從0度開始以30度為步長遞增,直到360度結束,每遞增一次就是一個迴圈。
(1)turtle.home()將位置和初始方向進行初始化,即:位置為(0.,0.),方向為0度。
(2)左轉i度。
(3)forward繪製直線,每回圈1次,直線長度遞增30.
(4)在直線的一端(除開原點的另一個端),使用write繪製文字,文字內容為該直線端的位置。
3、迴圈結束,以黑色畫筆(紅色填充)繪製原點,並繪製原點座標。

繪製函數圖形

程式2-7-12.py演示了繪製一元二次函數的影象。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2-7-12.py
import turtle

def getFunY(a,b,c,x):
    y=a*x*x+b*x+c
    return y

x=-10
a=0.6
b=0.2
c=0.8
while x<=10:
    turtle.up()
    turtle.goto(x,getFunY(a,b,c,x))
    turtle.dot(2)
    x+=0.1
input()

程式2-7-12.py的執行結果如下:

程式2-7-12.py的執行過程如下:
1、匯入turtle庫,為繪圖做準備。
2、定義getFunY函數,接收引數a、b、c以及x,函數體的程式碼完成根據一元二次函數值的計算。
3、定義a、b、c、x值,其中x值初始化為-10
4、while迴圈,迴圈條件是x<=10。
(1)up函數擡起畫筆
(2)goto函數移動到(x,y)處,其中x每次迴圈遞增0.1,y為根據a、b、c、x值計算的getFunY函數的返回值。
(3)dot函數落筆畫點。
x遞增0.1,整個迴圈x的值從-10增加到10。

到此這篇關於python3-函數與引數以及空值的文章就介紹到這了,更多相關python3函數與引數內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com