python的自定義函數(函數類型、def、range、rerun)

一、PyCharm基本設置

1、用Ctrl+鼠標滾輪--放大或縮小字體

python的自定義函數(函數類型、def、range、rerun)

搜索zoom

python的自定義函數(函數類型、def、range、rerun)

python的自定義函數(函數類型、def、range、rerun)

2、在Windows資源管理器打開文件或目錄

python的自定義函數(函數類型、def、range、rerun)

搜索keymap

python的自定義函數(函數類型、def、range、rerun)

設置成不常用的鍵即可,如F3。

3、代碼提示

python的自定義函數(函數類型、def、range、rerun)

搜索letter

python的自定義函數(函數類型、def、range、rerun)

二、自定義函數

python的自定義函數(函數類型、def、range、rerun)

1.爲什麼要使用函數

函數中的代碼一次編寫,多處運行;
函數可以讓代碼複用,減少代碼冗餘。

函數是組織好的,可重複使用的,用來實現單一,或相關聯功能的代碼段。

函數能提高應用的模塊性,和代碼的重複利用率。你已經知道Python提供了許多內建函數,比如print()。但你也可以自己創建函數,這被叫做用戶自定義函數。

假設我有這樣的需求:

python的自定義函數(函數類型、def、range、rerun)

但是我還是覺得太麻煩了,每次想吃飯的時候都要重複這樣的步驟。此時,我希望有這樣的機器:

  python的自定義函數(函數類型、def、range、rerun)

將重複的工作封裝到一起,我們只要向機器裏放入東西,就能得到我們想要的。

這也就是所謂的代碼重用。

例子

# 定義方法
def print_nums():
    """此處是函數功能的描述"""
    for i in range(1,11):
        print(i,end=" ")

# 1.三角形 2.正方形 3.梯形
key = int(input('請輸入要打印的圖形:'))
if key == 1:
    # 打印三角形的代碼
    print_nums()
    pass
elif key == 2:
    # 打印梯形的代碼
    pass
elif key == 3:
    # 正方形的代碼
    pass
輸出結果如下:
請輸入要打印的圖形:1
1 2 3 4 5 6 7 8 9 10 
進程已結束,退出代碼 0

分析一下

python的自定義函數(函數類型、def、range、rerun)

python的自定義函數(函數類型、def、range、rerun)

2、定義函數

你可以定義一個由自己想要功能的函數,以下是簡單的規則:

關鍵字: def

函數代碼塊以 def 關鍵詞開頭,後接函數標識符名稱和圓括號(),結尾處有冒號。

函數內第一行通常書寫註釋,表名該函數的意義

註釋後空一行,開始寫代碼塊,代碼庫要縮進

任何傳入參數和自變量必須放在圓括號中間。圓括號之間可以用於定義參數。

函數的第一行語句可以選擇性地使用文檔字符串—用於存放函數說明。

函數內容以冒號起始,並且縮進。

return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return相當於返回 None。

函數結束後,空2行

函數調用後空1行,再執行別的代碼

語法

#代碼如下
def functionname( parameters ):
  "函數_文檔字符串"
  function_suite
  return [expression]

默認情況下,參數值和參數名稱是按函數聲明中定義的的順序匹配起來的。

三、函數類型

Python函數可以使用的參數類型:

必備參數
命名參數
缺省參數
不定長參數

  • 參數類型:

  • ​ 1、位置參數:參數的位置(順序)很重要,形參和實參個數要匹配
  • ​ 2、關鍵字參數:對參數的位置要求不是很嚴格
  • ​ 3、默認值參數:
  • ​ (1)如果形參中指定了默認值,在實參中可以不傳遞該形參對應的實參
  • ​ (2)如果形參中指定了默認值,在實參彙總傳遞該參數後,最終參數以傳遞的實參爲準
  • ​ 4、不定長參數:
  • ​ (1)*a:接收傳遞單個值,保存爲元組
  • ​ (2)**b:接收鍵值對形式的參數,保存爲字典格式

    1、無參函數

無參函數實現和調用:

# 定義無參函數
def say_hi():
    """介紹自己的函數"""

    print('我是xgp,今年18歲,年收入xxxx元')

# 調用無參函數
say_hi()
輸出結果如下:
我是xgp,今年18歲,年收入xxxx元

進程已結束,退出代碼 0

2、帶參函數

下面說說帶參數的函數:

  • 形參:指的是形式參數,是虛擬的,不佔用內存空間,形參單元只有被調用的時才分配內存單元
  • 實參:指的是實際參數,是一個變量,佔用內存空間,數據傳遞單向,實參傳給形參,形參不能傳給實參

例子

# 定義帶參函數:形參(形式參數,模板)
def say_hi(name,age,money):
    """介紹自己的函數"""

    print('我是'+name+',今年'+str(age)+'歲,年收入'+str(money)+'元。')

# 調用帶參函數:實參(實際傳遞的參數)
say_hi('xgp',20,20000)
輸出結果如下:
我是xgp,今年20歲,年收入20000元。

進程已結束,退出代碼 0

注意事項:調用函數時,實參傳遞的個數
要與形參保持一致|

(1)位置參數

從上面的例子可以看出,實際參數和形式參數是一一對應的,如果調換位置,x和y被調用的時,位置也會互換,代碼如下:

def test(x,y):
    print(x)
    print(y)
print("--------互換前-----")
test(1,2)
print("--------互換後-----")
test(2,1)

#輸出
--------互換前-----
1
2
--------互換後-----
2
1

因爲定義x,y兩個形參,所以傳遞實參的時候,也只能傳遞兩個實參,多一個或少一個都是有問題的:

a:多傳遞一個參數

def test(x,y):
    print(x)
    print(y)
print("--------多一個參數----")
test(1,2,3)

#輸出
--------多一個參數----
Traceback (most recent call last):
  File "D:/PycharmProjects/pyhomework/day3/函數_帶參數.py", line 8, in <module>
    test(1,2,3)
TypeError: test() takes 2 positional arguments but 3 were given  #test()函數需要傳兩個實參,你傳了三個實參

b:少傳遞一個實參

def test(x,y):
    print(x)
    print(y)
print("--------少一個參數----")
test(1)

#輸出
--------少一個參數----
Traceback (most recent call last):
  File "D:/PycharmProjects/pyhomework/day3/函數_帶參數.py", line 8, in <module>
    test(1)
TypeError: test() missing 1 required positional argument: 'y'  
#沒有給y參數傳實參

(2)關鍵字參數

上面的位置參數,看起來有點死,必須形參和實參的位置一一對應,不然就會傳錯參數,爲了避免這種問題,就有了關鍵字參數的玩法:關鍵字傳參不需要一一對應,只需要你指定你的哪個形參調用哪一個實參即可;

def test(x,y):
    print(x)
    print(y)

print("--------互換前------")
test(x=1,y=2)
print("--------互換後------")
test(y=2,x=1)

#輸出
--------互換前------
1
2
--------互換後------
1
2

3、默認參數

調用函數時,默認參數的值如果沒有傳入,則被認爲是默認值。下例會打印默認的age,如果age沒有被傳入:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

#可寫函數說明
def printinfo( name, age = 35 ):
   "打印任何傳入的字符串"
   print "Name: ", name
   print "Age ", age
   return

#調用printinfo函數
printinfo( age=50, name="miki" )
printinfo( name="miki" )
輸出結果如下:
Name:  miki
Age  50
Name:  miki
Age  35

4、不定長參數

你可能需要一個函數能處理比當初聲明時更多的參數。這些參數叫做不定長參數,和上述2種參數不同,聲明時不會命名。基本語法如下:

def functionname([formal_args,] *var_args_tuple ):
   "函數_文檔字符串"
   function_suite
   return [expression]

*加了星號()的變量名會存放所有未命名的變量參數。不定長參數實例如下:**

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 可寫函數說明
def printinfo( arg1, *vartuple ):
   "打印任何傳入的參數"
   print "輸出: "
   print arg1
   for var in vartuple:
      print var
   return

# 調用printinfo 函數
printinfo( 10 )
printinfo( 70, 60, 50 )
輸出結果如下:
輸出:
10
輸出:
70
60
50

(1)例子

# 不定長參數的類型
def no_test(*args,**b):
    print((args))
    print(b)
no_test(1,2,3)
no_test(name='test',ages=18)
輸出結果如下:
(1, 2, 3)
{}
()
{'name': 'test', 'ages': 18}

5、匿名函數

python 使用 lambda 來創建匿名函數。

  • lambda只是一個表達式,函數體比def簡單很多。
  • lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
  • lambda函數擁有自己的命名空間,且不能訪問自有參數列表之外或全局命名空間裏的參數。
  • 雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不佔用棧內存從而增加運行效率。

語法

lambda函數的語法只包含一個語句,如下:

lambda [arg1 [,arg2,.....argn]]:expression

如下實例:

相加後的值爲 :  30
相加後的值爲 :  40

四、rerun傳遞列表類型數據

return語句[表達式]退出函數,選擇性地向調用方返回一個表達式。不帶參數值的return語句返回None。之前的例子都沒有示範如何返回數值,下例便告訴你怎麼做:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 可寫函數說明
def sum( arg1, arg2 ):
   # 返回2個參數的和."
   total = arg1 + arg2
   print "函數內 : ", total
   return total

# 調用sum函數
total = sum( 10, 20 )
輸出結果如下:
函數內 :  30

注意:在函數內沒有寫return語句的時候,默認return的是一個空對象。也就是就算沒寫,python內部也做了處理。

  此時,有部分人分不清函數的輸出和返回值的區別。

  這樣說吧,在函數裏print之類的操作能夠輸出內容,是因爲雖然函數的執行環境是獨立的,但代碼還是有效的。外部能進行的操作,函數內部也可以。但是並不是所有的函數在執行完畢後都有如此明顯的輸出效果,此時我們需要查看函數是否成功,或者說我放了米進去,你操作一番之後總要把飯給我拿出來吧。

  這就是函數中return的意義。返回一個對象。這個對象可以是對執行狀態的說明,也可以是處理後的結果等等。

1、return語句返回簡單類型

def test():
    return 'hello'
print(test())

# return 語句返回字典
def show_info(name,age):
    person = {'name':name,'age':age}
    return person

print(show_info('test',18))
輸出結果如下:
{'name': 'test', 'age': 18}

進程已結束,退出代碼 0

2、用戶問候

def say_hi(first_name,last_name):
    """返回完整名字"""
    full_name = first_name + ' ' + last_name
    return full_name

while True:
    print('請輸入您的姓名:')
    f_name = input('姓:')
    if f_name =='q':
        break

    l_name = input('名:')
    if l_name == 'q':
        break
        # 調用函數
    format_name = say_hi(f_name,l_name)
    print('hello'+format_name+'!')
輸出結果如下:
請輸入您的姓名:
姓:x
名:gp
hellox gp!

3、傳遞列表類型數據

def test(names):
    for name in names:
        print(name)
user_name = ['sdf','fsd','fewfwef','fwefe']
test(user_name)
輸出結果如下:
sdf
fsd
fewfwef
fwefe

進程已結束,退出代碼 0

5、range函數的練習

  1. 當只用一個變量調用這個函數時,這個變量指的是輸出的等差數列的終點,如range(5)
  2. 當給定兩個變量時,分別指輸出的起始值和終點,,如range(2, 5)
  3. 當給定三個變量時,在上一條的基礎上第三個變量指輸出時的步長,如range(2, 5, -1)

(假定我們調用這個函數時總是用整數或浮點數)

分析一下如何實現這個函數,下面給出我的思路作爲參考

  • 一共需要三個參數是顯而易見的;
  • 最直觀的感受是起始值是要有默認值的,如果不規定從哪裏開始,那就從0開始;
  • 步長也是要有默認值的,如果不規定,那麼步長是1;
  • 根據有默認值的參數要放在後面的原則,那麼最理所當然的參數設計是range_custom(stop, start=0, step=1)
  • 這個方案看上去可行,但是不滿足剛纔的後面兩個要求,如果我們這樣用兩個變量調用,起始值和終點是反的;
  • 我們加個判斷就可以了,如果start用了初始值,那麼說明我們調用的時候只給了一個參數,這個時候stop就是終點,如果start被重新賦值了說明給了至少兩個參數,那麼這時候把stop和start的值調換一下就可以了;
  • 現在這個函數似乎可以滿足大多數情況了,但是有一個bug,如果給定參數的時候給的start值就是0怎麼辦呢?如range_custom(-5, 0)按目前的規則會被翻譯成range(0, -5),但是我們的目的卻是range(-5, 0)
  • 所以start的初始值不應該是數字而是別的數據類型,爲了方便起見,我們把它的初始值賦爲None,我們的程序雛形就出來了。
def range_custom(stop, start=None, step=1):
    if start is None:
        return range(stop)
    return range(stop, start, step)

現在這個程序已經滿足我們的要求了,但是看上去不太舒服,可以改成

def range_custom(start, stop=None, step=1):
    if stop is None:
        return range(start)
    return range(start, stop, step)

現在這個函數的參數順序在邏輯上更好理解一些,可以說基本上滿足我們的要求了。當然,本例只是爲了說明參數的順序問題,並不是爲了實現range函數。事實上Python的range函數還包括參數實例化,生成器等知識,在後面我們應該還有機會再接觸它。

可選參數

說到可選參數,可能有的人見過,卻也不明白到底是什麼意思,它一般是這樣出現的

def func_option(*args):
    return args

*注意到我們聲明函數的時候在參數名前加了個``星號,這是聲明可選參數的方法。那麼可選參數到底有什麼用呢?**

可選參數的作用是用元組把所有多餘的變量收集起來,這個元組的名字就是這個可選參數名。在上例func_option中我們可以用任意多個變量調用它,比如a = func_option(1, 2, 3)那麼a就會是元組(1, 2, 3)。關於爲什麼是元組而不是列表,我們在上一篇Python進階-簡單數據結構中說過,元組在Python中往往是比列表更優先考慮使用的數據結構,具體原因在本文靠後深入自定義函數參數部分會討論。

我們剛纔說可選參數會收集多餘的變量。我這麼說是有原因的。

>>> def func_option(a, *args, c=2):
...     return args
...
>>> func_option2(1)
()
>>> func_option2(1, 2)
(2,)
>>> func_option2(1, 2, 3)
(2, 3)

*注意到我們的`args`把除了給普通參數的第一個變量以外的值都放進了元組中。這樣做導致了一個,問題在於我們的有默認值的參數如果不給定參數名地調用的話,就永遠只能用默認值了。而且如果我們在調用函數時不把有默認值的參數放在最後面程序還會報錯。**

>>> func_option2(c=1, 2, 3)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

那麼有沒有好的辦法能規避這個問題呢?我們可以試試把可選參數放在有默認值的參數後面。

>>> def func_option3(a, c=2, *args):
...     return args
...
>>> func_option3(1)
()
>>> func_option3(1, 2)
()
>>> func_option3(1, 2, 3)
(3,)
>>> func_option2(c=1, 2, 3)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

那麼這種形式的函數能不能解決之前的問題呢。看上去不行,不過我們知道了,調用函數的時候,要儘量把有默認值的參數放在靠後的位置賦予變量。那麼這兩種我們到底該用哪個方法呢?在實際操作中,我們傾向於將可選參數放在有默認值的參數之後,而且如果參數較多,我們傾向於調用函數時都會所有變量都加上參數名。而且實際操作中,其實可選參數用得不那麼多,相對來說,另一種可選參數其實用得更多。這種可選參數的形式一般是這樣

def func_optionkw(**kwargs):
    return args

在這種情況下,關鍵字可選參數都是作爲鍵值對保存在參數名的的字典中。也就是說,在調用函數時,在滿足一般參數以後,變量都應該以賦值語句的形式給出,等號左邊作爲鍵右邊作爲值。如果不這樣做,就會報錯了。

>>> func_optionkw(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: t2() takes 0 positional arguments but 1 was given

需要說明的是,一個自定義函數只能有一個可選參數,同時也可以有至多一個關鍵字參數。其中關鍵字參數應該放在普通可選參數之後。

現在我們來總結一下函數參數順序一般規律:

  • 一般參數放在最前面
  • 可選參數放在最後面
  • 關鍵字可選參數放在一般可選參數後面
  • 函數調用時儘量把有默認值的參數對應的變量放在靠後的位置
  • 如果參數比較多,調用函數時,最好所有變量都指明參數名

以上這些,有的是爲了防止函數定義時出錯,有的是爲了防止函數調用時出錯,總之,應該養成良好的編程習慣。

五、變量作用域

一個程序的所有的變量並不是在哪個位置都可以訪問的。訪問權限決定於這個變量是在哪裏賦值的。

變量的作用域決定了在哪一部分程序你可以訪問哪個特定的變量名稱。兩種最基本的變量作用域如下:

  • 全局變量
  • 局部變量

六、全局變量和局部變量

定義在函數內部的變量擁有一個局部作用域,定義在函數外的擁有全局作用域。

局部變量只能在其被聲明的函數內部訪問,而全局變量可以在整個程序範圍內訪問。調用函數時,所有在函數內聲明的變量名稱都將被加入到作用域中。如下實例:

實例(Python 2.0+)

#!/usr/bin/python
# -*- coding: UTF-8 -*-

total = 0 # 這是一個全局變量
# 可寫函數說明
def sum( arg1, arg2 ):
   #返回2個參數的和."
   total = arg1 + arg2 # total在這裏是局部變量.
   print "函數內是局部變量 : ", total
   return total

#調用sum函數
sum( 10, 20 )
print "函數外是全局變量 : ", total
輸出結果如下:
函數內是局部變量 :  30
函數外是全局變量 :  0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章