Python自動化運維之三、函數、lambda、遞歸

1、函數

函數的基礎概念:
  函數是python爲了代碼最大程度地重用和最小化代碼冗餘而提供的基本結構
  函數是一種設計工具,它能讓程序員將複雜的系統分解爲可管理的部件
  函數用於將相關功能打包並參數化
  在python中能夠建立4種函數
    (1)全局函數:定義在模塊
    (2)局部函數:嵌套於其它函數中
    (3)lambda函數:表達式,如需屢次調用
    (4)方法:與特定數據類型關聯的函數,而且只能與數據類型關聯一塊兒使用
  python提供了不少內置函數html


建立函數:python

def functionName(arg1,arg2,...):
  suite
   return 

函數的定義主要有以下要點:git

  • def:表示函數的關鍵字
  • 函數名:函數的名稱,往後根據函數名調用函數
  • 函數體:函數中進行一系列的邏輯計算,如:發送郵件、計算出 [11,22,38,888,2]中的最大數等...
  • 參數:爲函數體提供數據
  • 返回值:當函數執行完畢後,能夠給調用者返回數據。

一些相關的概念:
  def是一個可執行語句
    所以能夠出如今任何可以使用語句的地方,甚至能夠嵌套於其餘語句,例如if或while中
  def建立了一個對象並將其賦值給一個變量名(即函數名),函數體則存在內存
  return用於返回結果對象,其爲可選;無return語句的函數自動返回None對象
    返回多個值時,彼此間使用逗號分隔,且組合爲元組形式返回一個對象
    函數一旦執行到return,函數就終止了,若是return下面還有執行語句則終止
  def語句運行以後,能夠在程序中經過函數後附加()進行調用程序員

函數做用域:
  python建立、改變或查找變量名都是在名稱空間中進行
  在代碼中變量名被賦值的位置決定了其能被訪問到的範圍
  函數定義了本地做用域,而模塊定義了全局做用域編程

    1.全局變量所有用大寫表示
    2.全局變量均可以被訪問,函數內部的變量則爲本地做用域
    3.在函數內若是要修改全局變量,須要global
    4.特殊:字典,列表能夠在函數內修改,可是不能從新賦值tomcat

更多做用域服務器

NAME = 'tomcat'

def f1():
    age = 18
    global NAME
    NAME = 'xiao'
    print(age,NAME)

def f2():
    age = 27
    print(age,NAME)

f1()
f2()

函數的參數:
  默認狀況下,參數經過其位置進行傳遞,從左至右,這意味着,必須精確地傳遞和函數頭部參數同樣多的參數
  但也能夠經過關鍵字參數、默認參數或參數容器等改變這種機制
    (1)普通參數:定義函數時從左至右
    (2)默認參數:定義函數時是使用"name=value"的語法直接給變量一個值,從而傳入的值能夠少於參數個數
    (3)指定參數:調用函數時指定"name形式參數=value實際參數"的語法經過參數名進行匹配
    (4)動態參數:定義函數時形式參數中收集任意多基於普通參數
      定義函數時使用* :收集普通參數,返回元組,*args
      定義函數時使用**:收集指定參數,返回列表,**kwargs
    (5)動態參數解包:調用函數時,使用**開頭的參數,從而傳遞任意多基於普通或指定參數

注意:定義函數時
  1.混用普通參數和默認參數,應當把默認參數寫到右側
  2.混用有默認和無默認值的參數時,無默認值放左側app

 

一、返回值ide

函數是一個功能塊,該功能到底執行成功與否,須要經過返回值來告知調用者。函數式編程

以上要點中,比較重要有參數和返回值:

def 發送短信():
       
    發送短信的代碼...
   
    if 發送成功:
        return True
    else:
        return False
   
while True:
       
    # 每次執行發送短信函數,都會將返回值自動賦值給result
    # 以後,能夠根據result來寫日誌,或重發等操做
   
    result = 發送短信()
    if result == False:
        記錄日誌,短信發送失敗...

二、參數

沒有參數的狀況

#!/usr/bin/env python
# -*- coding:utf-8 -*-

'''
1.須要開啓郵箱服務sendmail
2.郵箱服務器須要開啓SMTP服務
'''

def sendmail():
    try:
        import smtplib
        from email.mime.text import MIMEText
        from email.utils import formataddr

        msg = MIMEText('郵件內容', 'plain', 'utf-8')
        msg['From'] = formataddr(["發件人", 'pythonxiao@126.com'])
        msg['To'] = formataddr(["收件人", '329275108@qq.com'])
        msg['Subject'] = "郵件主題"

        server = smtplib.SMTP("smtp.126.com", 25)
        server.login("pythonxiao@126.com", "xiaozhiqi2016")
        server.sendmail('pythonxiao@126.com', ['329275108@qq.com', ], msg.as_string())
        server.quit()
    except:
        return False
    else:
        return True

ret = sendmail()
if ret == True:
    print("發送成功")
else:
    print("發送失敗")

有參數的狀況:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def sendmail(email,content):
    try:
        import smtplib
        from email.mime.text import MIMEText
        from email.utils import formataddr

        msg = MIMEText(content, 'plain', 'utf-8')
        msg['From'] = formataddr(["發件人", 'pythonxiao@126.com'])
        msg['To'] = formataddr(["收件人", '329275108@qq.com'])
        msg['Subject'] = "郵件主題"

        server = smtplib.SMTP("smtp.126.com", 25)
        server.login("pythonxiao@126.com", "xiaozhiqi2016")
        server.sendmail('pythonxiao@126.com', [email, ], msg.as_string())
        server.quit()
    except:
        return "失敗"
    else:
        return 'cc'

while True:
    msg = input("請輸入郵箱地址:")

    #實際參數
    ret = sendmail(msg,"SB")
    if ret == 'cc':
        print("發送成功")
        break
    else:
        print("發送失敗")

從上面例子能夠看出有參數的函數表現的很是靈活可擴展!

函數的有三中不一樣的參數(定義函數時):

  • 普通參數
  • 默認參數
  • 動態參數

  指定參數和動態參數解包是發生在調用函數

(1)# xxoo爲普通參數也叫形式參數,簡稱:形參
def f1(name):
    print(name)

# 'test' 叫作函數的實際參數,簡稱:實參
f1('tomcat')
普通參數
(2)# name 是普通參數,ab=5是默認參數
def f1(name,ab=5):
    print(name,ab)

# 指定參數
f1('tomcat',12)

# 使用默認參數
f1('tomcat')

注意:默認參數須要放在參數列表最後
默認參數
(3)# 動態參數(1):*args 返回的是一個元組
def f1(*args):
    print(args,type(args))

# 執行方式一    
f1(11)

# 若是傳入一個列表,則這個列表是看成元組中的一個元素
li = ['a','b','c']
f1(li)

# 執行方式二:執行函數時有*,把全部迭代對象拆分爲單個元素做爲元組的元素,如傳入列表,會把列表中每個元素遍歷添加到元組中看成一個元素
f1(*l1)
動態參數一
(4)#動態參數(2):**kwargs 返回的是一個字典
def f1(**kwargs):
    print(args,type(args))
    
# 執行方式一:只能傳入指定參數    
f1(n1='alex',n2=18)

dic = {'k1':'v1','k2':'v2'}
f1(kk=dic)

# 執行方式二:實際參數若是有**,傳入的應該是一個字典,會把每一對鍵值對像不帶**同樣把指定參數傳入函數中
f1(**dic)
動態參數二
(5)# 俗稱萬能參數
def f1(*args,**kwargs):
    print(args,type(args))
    print(kwargs,type(kwargs))

# 執行方式一
f1(11,22,33,k1='v1',k2='v2')

# 執行方式二
l1 = [1,2,3,4]
d1 = {'a':'xiao','b':'zhi','c':'qi'}
f1(*l1,**d1)
俗稱萬能參數

在python中能夠常常看到萬能參數,好比str.format()用於格式化的方法,這裏用不一樣的參數傳遞方式實現相同的效果

>>> s1 = 'i am {0}, age {1}'.format('alex',18)
>>> print(s1)
i am alex, age 18

>>> s2 = 'i am {0}, age {1}'.format(*['alex',18])
>>> print(s2)
i am alex, age 18

>>> s3 = 'i am {0}, age {1}'.format(*('alex',18))
>>> print(s3)
i am alex, age 18

>>> s4 = 'i am {name}, age {age}'.format(name='alex',age=18)
>>> print(s4)
i am alex, age 18

>>> dic = {'name':'alex','age':18}
>>> s5 = 'i am {name}, age {age}'.format(**dic)
>>> print(s5)
i am alex, age 18

3.補充:

(1).在定義相同函數時,後一個函數名會指向新的內存對象,函數名是函數體在內存中的引用,就像變量賦值同樣,變量名是對對象在內存中的引用

def f1(a,b):
    return a + b

def f1(a,b):
    return a * b

ret = f1(8,8)
print(ret)

(2).函數在傳遞參數的時候是內存中的引用,而不是複製,因此l1的值是[1,2,3,4,999]

def f1(a1):
    a1.append(999)

l1 = [1,2,3,4]
f1(l1)

print(l1)

 稍微改變下,用一個變量來接收函數的返回值,這裏的l1的值不是[1,2,3,4,999],而是None,由於函數內並無定義返回值,因此爲None

def f1(a1):
    a1.append(999)

l1 = [1,2,3,4]
l1 = f1(l1)

print(l1)

 

函數式編程:

之後寫函數按照下面這個例子來編寫,規範,這是一個登陸註冊的函數編程

1.函數與函數間隔2行

2.函數須要註釋,便於記憶

3.函數名須要見名知意

 db文件格式

admin|123
xiao|12345
db

 代碼

#!/usr/bin/env python
# coding: utf8


def datainput():
    username = input("input your username:")
    password = input("input your password:")
    return username,password


def login(username,password):
    f = open('db','r')
    for line in f:
        data = line.strip().split('|')
        if data[0] == username and data[1] == password:
            return True
    return False


def register(username,password):
    f = open('db','r')
    for line in f:
        user = line.strip().split('|')
        #print(user)
        if username in user:
            return False
    else:
        f = open('db','a')
        userdata = "\n" + username + "|" + password
        f.write(userdata)
        f.close()
        return True


def main():
    num  = input("1.登陸,2.註冊:")
    if int(num) == 1:
        data = datainput()
        result = login(data[0],data[1])
        if result:
            print('登陸成功')
        else:
            print('登陸失敗')
    elif int(num) == 2:
        data = datainput()
        ret = register(data[0],data[1])
        if ret:
            print("註冊成功")
        else:
            print("註冊失敗,用戶已存在")


main()

2、三元運算符  

  三元表達式,三元運算,三目運算符都是指同一個意思:能夠簡化條件語句的縮寫,可使代碼看起來更加簡潔,三目能夠簡單的理解爲有三個變量,它的形式是這樣的 name= k1 if 條件 else k2 ,若是條件成立,則 name=k1,不然name=k2,下面從代碼裏面來加深一下理解,從下面的代碼明顯能夠看出三目運算符可使代碼更加簡潔。

a=1
b=2
if a<b:                     #通常條件語句的寫法
    k=a
else:
    k=b
     
c=a if a<b else b         #三目運算符的寫法,若是a<b爲True,則c=a,不然c=b

 

3、lambda表達式

對於簡單的函數,也存在一種簡便的表示方式,即:lambda表達式

# ###################### 普通函數 ######################
# 定義函數(普通方式)
def func(arg):
    return arg + 1
    
# 執行函數
result = func(123)
    
# ###################### lambda ######################
    
# 定義函數(lambda表達式)
my_lambda = lambda arg : arg + 1
    
# 執行函數
result = my_lambda(123)

 lambda表達式會自動return返回值,條件爲真返回True,條件爲假返回False.

 

4、遞歸

  若是一個函數在其內部調用它本身,就叫作遞歸,可是遞歸的時候要設置一個退出遞歸的條件,否則會一直遞歸下去,變成一個死循環。從另外一個方面來講,遞歸其實和循環實際上是等價的。想要明白遞歸的話,咱們先從實際的例子上來講明這一點,好比說咱們要寫一個階乘函數 f(n)算出n的階乘,階乘函數實現的方法不少,下面講如何用遞歸實現

def f(n):
    if 0==n:                  # n=0 的話直接返回空,對用戶輸入的零進行判斷
        return None
    elif 1==n:                # n=1 的話就再也不遞歸
        return n
    else:
        return n*f(n-1)      # 遞歸在執行f(n-1) 直到f(1)
print(f(5))                  # 120
'''
    f(5)的執行過程以下
        ===> f(5)
        ===> 5 * f(4)
        ===> 5 * (4 * f(3))
        ===> 5 * (4 * (3 * f(2)))
        ===> 5 * (4 * (3 * (2 * f(1))))
        ===> 5 * (4 * (3 * (2 * 1)))
        ===> 5 * (4 * (3 * 2))
        ===> 5 * (4 * 6)
        ===> 5 * 24
        ===> 120
'''

再來一個例子:

def func(n):
    n += 1
    if n >= 4:
        return 'end'
    return func(n)

r = func(4)
print(r)

end #這是執行結果

下面的圖幫助理解

傳入1的時候,n=2不知足n>=4這個條件,return func(2)

傳入2的時候,n=3不知足n>=4這個條件,return func(3)

傳入3的時候,n=4知足n>=4這個條件,return end

return end --> return func(3) --> return func(2) --> r = func(1) 因此r的返回值就是end

 

練習:

一、寫函數,計算傳入字符串中【數字】、【字母】、【空格] 以及 【其餘】的個數 

def fun(s):
    digitnum, alphanum, sapcenum, othernum=0,0,0,0
    for i in s:
        if i.isdigit():
            digitnum+=1
        elif i.isalpha():
            alphanum+=1
        elif i.isspace():
            sapcenum+=1
        else:
            othernum+=1
    return (digitnum,alphanum,sapcenum,othernum)

二、寫函數,判斷用戶傳入的對象(字符串、列表、元組)長度是否大於5  

def fun(s):
    ret=False
    if isinstance(s,str) or isinstance(s,str) or isinstance(s,tuple):
       if len(s)>5:
           ret=True
    return ret

三、寫函數,檢查用戶傳入的對象(字符串、列表、元組)的每個元素是否含有空內容

def fun(s):
    ret=False
    if isinstance(s, str) or isinstance(s, str) or isinstance(s, tuple):
        for i in s:
           if i=='':
               ret=True
               break
    return ret

四、寫函數,檢查傳入列表的長度,若是大於2,那麼僅保留前兩個長度的內容,並將新內容返回給調用者。

def fun(s):
    if isinstance(s,list):
        if len(s)>2:
            return s[0:2]
    return None

五、寫函數,檢查獲取傳入列表或元組對象的全部奇數位索引對應的元素,並將其做爲新列表返回給調用者。

def fun(s):
    if isinstance(s,list) or isinstance(s,tuple):
        l=[]
        for i in range(1,len(s),2):
            l.append(s[i])
        return l
    return None

六、寫函數,檢查傳入字典的每個value的長度,若是大於2,那麼僅保留前兩個長度的內容,並將新內容返回給調用者。

def fun(s):
    if isinstance(s,dict):
        for i in s:
            if len(s[i])>2:
                s[i]=s[i][0:2]
    return s

七、寫函數,利用遞歸獲取斐波那契數列中的第 10 個數,並將該值返回給調用者。

def fun(n):
    if 1==n :
        return 0
    elif 2==n:
        return 1
    else:
        return fun(n-1)+fun(n-2)
相關文章
相關標籤/搜索