【8】python之函數


一、函數是什么

函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不同的,編程中的函數在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子過程或子程序),在Pascal中叫做procedure(過程)和function,在C中只有function,在Java里面叫做method。

定義: 函數是指將一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名即可。

二、使用函數的好處

1、簡化代碼
2、提高代碼的復用性
3、代碼可擴展

三、python中函數的定義

定義函數使用def關鍵字,后面是函數名,函數名不能重復

def fun():#定義一個函數,后面是函數名
    print("Hello World")#函數體

當然上面的函數其實沒有什么卵用,就是寫個函數定義的例子而已。

四、函數的參數

1、形參和實參

函數在調用的時候,可以傳入參數,有形參和實參,簡單點說,形參就是函數接收的參數,而實參就是你實際傳入的參數。
形參:形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。
實參:實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。函數調用結束返回主調用函數后則不能再使用該形參變量。

def calc(x,y):#定義一個函數,參數有x和y,x和y就是形參
   print(x*y)#輸出x乘以y的值
calc(5,2)#調用上面定義的函數,5和2就是實參

2、函數的四種形參類型

(1)位置參數

位置參數,字面意思也就是按照參數的位置來進行傳參,有幾個位置參數在調用的時候就要傳幾個,否則就會報錯了。

# name,sex為位置參數/必填參數
def my(name,sex):
    print(name,sex)
    return name
my('wwww','')

(2)默認參數

默認參數就是在定義形參的時候,給函數默認賦一個值,比如說數據庫的端口這樣的,默認給它一個值,這樣就算你在調用的時候沒傳入這個參數,它也是有值的

# port=3306為默認值參數
def connect(ip,port=3306):
    print(ip,port)

#如果給一個port值,則傳新給的值
connect('118.1.1.1',3307)
#如果不填,則使用默認參數
connect('118.1.1.1')

 

(3)可變參數

1、可變參數用*來接收,不是必傳的;
2、它把傳入的元素全部都放到了一個元祖里;
3、不顯示參數個數,后面想傳多少個參數就傳多少個,它用在參數比較多的情況下
4、如果位置參數、默認值參數、可變參數一起使用的的話,可變參數必須在位置參數和默認值參數后面。

#實例:發送報警短信 參數前面加*代表參數組
def send_sms(*phone_num):
    
    #方法1,返回的是元祖
    print(phone_num)
    #方法2,用下面循環的方法,不打印整個元祖,而是打印每一個元素
    # for p in phone_num:
    #     print(p)


send_sms()# 不傳參數
send_sms(150)# 傳1個
send_sms(151,152,153)# 傳N個

# 執行后結果是:
# ()
# (150,)
# (151, 152, 153)

 

(4)關鍵字參數

1、關鍵字參數使用**來接收
2、返回的是字典
3、不限制參數個數,非必傳
4、當然也可以和上面的幾種一起來使用,如果要一起使用的話,關鍵字參數必須在最后面

def send_sms2(**phone_num):
    print(phone_num)

send_sms2()
send_sms2(name='xiaohei',sex='nan')
send_sms2(addr='北京',country='中國',aa='hahaha')

# 執行后結果是:
# {}
# {'name': 'xiaohei', 'sex': 'nan'}
# {'addr': '北京', 'country': '中國', 'aa': 'hahaha'}

 

(5)以上四種放在一起使用

如果一定要一起用的話,要按下面的順序寫,不能換順序,否則會出錯
1、位置參數;2、默認值參數;3、可變參數;4、關鍵字參數

def my(name,country='china',*args,**kwargs):
    print(name)
    print(country)
    print(args)
    print(kwargs)

# 看看都是誰接收到了誰

my('xiaohong','2','3','4','5',a='6',b='7')

 

五、函數的返回值-return語句

每個函數都有返回值,如果沒有在函數里面指定返回值的話,在python里面函數執行完之后,默認會返回一個None,函數也可以有多個返回值,如果有多個返回值的話,會把返回值都放到一個元組中,返回的是一個元組。

為什么要有返回值呢,是因為在這個函數操作完之后,它的結果在后面的程序里面需要用到。

函數中的返回值使用return,函數在遇到return就立即結束。

1、什么樣的函數需要returen,什么樣的不需要?下面這個只是顯示當前日期,就不需要return

import datetime
def get_today():
    print(datetime.datetime.today())

 


2、函數的返回值寫法

#只有一個返回值
def calc(x,y):#這個就是定義了一個有返回值的函數
    c = x*y
    return c,x,y
res = calc(5,6)#把函數的返回結果賦值給res
print(res)


# 當return有多個值時
def my3():
    a=1
    b=2
    c=3
    # a,b,c=1,2,3#也可以這樣寫
    return a,b,c

a,b,c=my3()
s=my3()


print(s)
print(a,b,c)


# 返回結果分別是
# (1, 2, 3)    # 元祖
# 1 2 3        # int

 


3、returen的另一個作用

def my2():
    for i in range(50):
        return i
print(my2())
#我們以為會返回0~49,實際運行返回了0,這是因為
#return 有2個作用
# 1、結束函數,只要函數里面遇到return,函數立即結束運行
# 2、返回函數處理的結果

 

六、局部變量和全局變量

1、局部變量意思就是在局部生效的,出了這個變量的作用域,這個變量就失效了。
2、全局變量的意思就是在整個程序里面都生效的,在程序最前面定義的都是全局變量。
3、全局變量如果要在函數中修改的話,需要加global關鍵字聲明,如果是list、字典和集合的話,則不需要加global關鍵字,直接就可以修改。
4、任何函數都可以修改,所以盡量少用全局變量,原因1不夠安全。原因2全局變量一直占用內存.

#如果兩種變量都有,會先用局部變量,當沒有局部變量則用全局變量

#全局變量,在函數的外面
name='wangcan'

def get_name():

    # 聲明修改全局變量
    global name

    # 局部變量,定義在函數內部
    name='hailong'
    print('函數里面的name:'+name)

def get_name2():
    print('get_name2:',name)

get_name2()  #第一調用,打印wangcan

get_name()  #第二調用,打印函數內的name:hailong
print('函數外面的name:'+name)# 最后打印,因為有函數聲明了全局變量,所以打印的是:hailong


#最后的結果是
# get_name2: wangcan
# 函數里面的name:hailong
# 函數外面的name:hailong

 

七、遞歸調用

在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。

遞歸調用的意思就是,在這個函數內部自己調用自己,就有點循環的意思,寫個遞歸,如下:

#遞歸應用舉例
def test1():
    num = int(input('please enter a number:'))
    if num%2==0:#判斷輸入的數字是不是偶數
       return True #如果是偶數的話,程序就退出了,返回true
    print('不是偶數請重新輸入!')
    return test1()#如果不是偶數的話繼續調用自己,輸入值
print(test1())#調用test

 


遞歸調用的特性:

1. 必須有一個明確的結束條件

2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少

3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)

八、小練習:校驗小數類型

小練習:輸入一個字符串,判斷是否是小數
提示:
1、1.5小數點個數為1   '1.5'.count('.')==1
2、a.3小數點左邊和右邊都是整數,用點分隔  st.isdigit()
3、負小數 負號開頭並且只有一個負號  只有一個,什么開頭

def check_float(s):

    '''
    這個函數的作用就是判斷傳入的字符串是否合法的小數
    :param s: 傳入一個字符串
    :return: True/False
    '''

    # 不管傳什么類型,先轉成字符換
    s = str(s)

    #判斷小數點個數為1
    if s.count('.')==1:


        # 用點分隔#-1.5   [-1.5]
        res = s.split('.')

        left,right=res
        if left.isdigit() and right.isdigit():# 判斷是否只由數字組成
        # if res[0].isdigit() and res[1].isdigit():# 判斷是否只由數字組成,上面兩句也可以這樣寫
            print('是小數')
            return True


        # 以負號開頭,並left中且第一個字符后面的都是整數(用到了切片),right是整數
        elif left.startswith('-') and left[1:].isdigit() and right.isdigit():
        # elif res[0].startswith('-') and res[0][1:].isdigit() and res[1].isdigit():
            print('是小數')
            return True

    return False

print(check_float('1.3'))
print(check_float('-1.3'))
print(check_float('---1.3'))
print(check_float('a.3'))
print(check_float('1..3'))

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM