• Python自动化运维之3、函数、lambda、递归


    一、函数

    函数的基础概念:
      函数是python为了代码最大程度地重用和最小化代码冗余而提供的基本结构
      函数是一种设计工具,它能让程序员将复杂的系统分解为可管理的部件
      函数用于将相关功能打包并参数化
      在python中可以创建4种函数
        (1)全局函数:定义在模块
        (2)局部函数:嵌套于其它函数中
        (3)lambda函数:表达式,如需多次调用
        (4)方法:与特定数据类型关联的函数,并且只能与数据类型关联一起使用
      python提供了很多内置函数


    创建函数:

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

    函数的定义主要有如下要点:

    • def:表示函数的关键字
    • 函数名:函数的名称,日后根据函数名调用函数
    • 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
    • 参数:为函数体提供数据
    • 返回值:当函数执行完毕后,可以给调用者返回数据。

    一些相关的概念:
      def是一个可执行语句
        因此可以出现在任何能够使用语句的地方,甚至可以嵌套于其他语句,例如if或while中
      def创建了一个对象并将其赋值给一个变量名(即函数名),函数体则存在内存
      return用于返回结果对象,其为可选;无return语句的函数自动返回None对象
        返回多个值时,彼此间使用逗号分隔,且组合为元组形式返回一个对象
        函数一旦执行到return,函数就终止了,如果return下面还有执行语句则终止
      def语句运行之后,可以在程序中通过函数后附加()进行调用

    函数作用域:
      python创建、改变或查找变量名都是在名称空间中进行
      在代码中变量名被赋值的位置决定了其能被访问到的范围
      函数定义了本地作用域,而模块定义了全局作用域

        1.全局变量全部用大写表示
        2.全局变量都可以被访问,函数内部的变量则为本地作用域
        3.在函数内如果要修改全局变量,需要global
        4.特殊:字典,列表可以在函数内修改,但是不能重新赋值

    更多作用域

    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.混用有默认和无默认值的参数时,无默认值放左侧

    1、返回值

    函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。

    以上要点中,比较重要有参数和返回值:

    def 发送短信():
           
        发送短信的代码...
       
        if 发送成功:
            return True
        else:
            return False
       
    while True:
           
        # 每次执行发送短信函数,都会将返回值自动赋值给result
        # 之后,可以根据result来写日志,或重发等操作
       
        result = 发送短信()
        if result == False:
            记录日志,短信发送失败...

    2、参数

    没有参数的情况

    #!/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 = "
    " + 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()

    二、三元运算符  

      三元表达式,三元运算,三目运算符都是指同一个意思:可以简化条件语句的缩写,可以使代码看起来更加简洁,三目可以简单的理解为有三个变量,它的形式是这样的 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

    三、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.

    四、递归

      如果一个函数在其内部调用它自己,就叫做递归,但是递归的时候要设置一个退出递归的条件,不然会一直递归下去,变成一个死循环。从另一个方面来说,递归其实和循环其实是等价的。想要明白递归的话,我们先从实际的例子上来说明这一点,比如说我们要写一个阶乘函数 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

    练习:

    1、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 

    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)

    2、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于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

    3、写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容

    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

    4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

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

    5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。

    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

    6、写函数,检查传入字典的每一个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

    7、写函数,利用递归获取斐波那契数列中的第 10 个数,并将该值返回给调用者。

    def fun(n):
        if 1==n :
            return 0
        elif 2==n:
            return 1
        else:
            return fun(n-1)+fun(n-2)
  • 相关阅读:
    Leetcode 191.位1的个数 By Python
    反向传播的推导
    Leetcode 268.缺失数字 By Python
    Leetcode 326.3的幂 By Python
    Leetcode 28.实现strStr() By Python
    Leetcode 7.反转整数 By Python
    Leetcode 125.验证回文串 By Python
    Leetcode 1.两数之和 By Python
    Hdoj 1008.Elevator 题解
    TZOJ 车辆拥挤相互往里走
  • 原文地址:https://www.cnblogs.com/xiaozhiqi/p/5742973.html
Copyright © 2020-2023  润新知