zoukankan      html  css  js  c++  java
  • Python函数

    前言:

    函数在编程中有着至关重要的地位,它组织代码、使代码复用,下面我们将分类介绍一下Python函数的基本使用、闭包、装饰器等;

    函数的使用阶段:

    定义阶段:定义就是把一段代码,赋值给函数

    调用阶段:一定要先定义,再调用

    函数的组成结构:

    1、函数名    

    2、 函数体

    3、返回值     (1-3属于函数定义阶段)

    4、调用阶段

    5、表达式形式调用函数可以保存函数返回值   /  语句形式调用函数执行后的返回值 不会被保存下来;

    def my_sum(x,y):            #def语句 定义的函数名
        res=x if x > y else y  #函数体
        return res             #函数的执行结果,人过留名,雁过留声;函数执行结束后,如果没有返回值,就是 none
    a=my_sum(7,8)               # 函数调用阶段  把函数执行的结果,赋值给变量,保存起来
    print(a)                    #打印函数的执行结果
    print(my_sum(8,9))          #语句形式 调用函数,不会保存函数的返回值;

    函数的参数

    函数的可变参数: *args   **args   (args是变量名可以为任何字符)

    在实参的角度

    *arga:在按位置传值的情况下,多余的 组织成 元组 值赋值给*args 包含多个位置参数

    1 def chen (*b):  #  *b传入形参的是元组,其长度可以无穷无尽。 b=(1,2,3,4,5,6,7)
    2     sum=0
    3     for i in b:
    4         sum+=i
    5     return sum
    6 
    7 print(chen(1,2,3,4,5,6,7))

    在形参的角度

    形参混合使用优先级:位置传参、args传参、默认传参

    def foo (a,*b,c=2):  # *b 在形参的角度来讲属于 位置传参 所以一定要在 默认传参之前
        print(a)
        print(*b)
        print(c)
    
    foo(1,2,4,5,6,c=7)

    *(1,2,3,4)或者 *[1,2,3,4]就相当于 把元组、列表这些序列 分解、打散 分别给实参;

    
    
    
    



    def foo (a,b,c,d):
        print(a)
        print(b)
        print(c)
        print(d)
    
    foo( *(1,2,3,4))   # *(1,2,3,4) 元组也可以在实参数上 传值   *(1,2,43,4)== *args
    

    **arges

    从实参角度

    在关键字传值时,把多余的实参  组织成 字典 形式 赋值给形参

    1 def foo (a,**b): #从形参的角度来说 在关键字传值得情况下,把多余的实参赋给 **b
    2     print(a)
    3     print(b)
    4 
    5 
    6 foo( 1,b=2,c=3 ,d=4) 

    运行结果:

    1
    {'b': 2, 'c': 3, 'd': 4}

    (*a,**b): #接受任意 实参 ,可以位置传参,可以是关键字传参 

     1 def foo (*a,**b): #形参可以接受任意实参 ,可以是位置传参,可以是关键字传参
     2     print(a)
     3     print(b)
     4 
     5 
     6 foo( 1,2,3,4,5,b=2,c=3 ,d=4)
     7 
     8 运行结果:
     9 (1, 2, 3, 4, 5)
    10 {'b': 2, 'c': 3, 'd': 4}

    闭包

    前戏

    x=1
    def f1():
        x=2
        def f2():
            print(x)
        return f2
    
    f3=f1()
    x=2222222222
    f3() #函数的作用域已经在函数定义阶段就已经确立了,调用函数阶段不管函数在哪个位置执行,都要回到原来确定好作用域;

    执行结果:2

    个人理解闭包函数的作用 (实现装饰器):

    闭包可以保存住外部函数的变量(状态),既然内部函数打包了外部作用域的状态,在这个基础上增加外部函数的功能,这不是正是函数装饰器吗?

    x=1
    
    def f1():
        x=2
        y=6
        def f2():
            print(x)
            print(y)
        return f2
    
    f3=f1()  #f3 =f1内部的f2
    x=2222222222
    f3()
    '''
    函数的作用域已经在函数定义阶段就已经确立了,调用函数阶段不管函数在哪个位置执行,
    都要回到原来定义的位置寻找作用域关系!
    '''
    print(f3.__closure__[0].cell_contents ) #获取内部函数引用外部作用域的值
    print(f3.__closure__[1].cell_contents )

     将以下joson数据解析成sql语句(使用闭包,包住relation变量

    {"filters": [
    {"func": "contains", "field": "title", "args": ["CHECKPOINT"]},
    {"func": "contains_one", "field": "tag", "args": [10]}
    ],
    "relation": "and"
    }
    import pymysql
    import datetime
    import json
    from conf import mysql_conf
    
    
    #MySQL基础配置类
    class MySQLHandler(object):
        def __init__(self,mysql_conf):
            self.mysql_conf=mysql_conf
        def query(self, sql):
            self.ret = []
            mysql_conn = pymysql.connect(**self.mysql_conf)
            cursor = mysql_conn.cursor()
            cursor.execute(sql)
            columns = [x[0] for x in cursor.description]
            for row in cursor.fetchall():
                d = dict(zip(columns, row))
                self.ret.append(d)
            cursor.execute('commit')
            cursor.close()
            mysql_conn.close()
            return self.ret
        def update(self, sql):
            self.ret = []
            mysql_conn = pymysql.connect(**self.mysql_conf)
            cursor = mysql_conn.cursor()
            cursor.execute(sql)
            cursor.execute('commit')
            cursor.close()
            mysql_conn.close()
            return self.ret
        @property
        def global_alarm_rules(self):
            ret = self.query(sql='select * from alarm_rules where in_use=-2')
            return ret
    
    #获取alarm_rules表的1条记录的json数据进行解析 + 拼sql
    class RuleHandler(MySQLHandler):
        def __init__(self,mysql_conf):
            super().__init__(mysql_conf)
    
        def parse_rules(self,conditions):#使用闭包,包住relation变量
            filters = [self.parse_filters(**x) for x in  conditions['filters']]
            relation=conditions['relation']
            self.select_sql = ''
            def f():
                for x in filters:
                    self.select_sql+= ' %s ' %(relation)+x()
            return f
    
        def parse_actions(self,action):
            self.update_sql=''
            if action['type'] == 'mark':
                def do():
                    self.update_sql='process_status = "%s"'%(action['args'])
                return do
    
        def parse_filters(self, field, func, args):
            sql = False
            if func == 'equals':
                sql = '%s = %s' % (field, args)
            elif func == 'contains':
                sql = '{0} like "%%{1}%%"'.format(field,args)
            elif func == 'during':
                sql = 'send_time between "%s" and "%s"' % (self.during_this_period(*args))
            return (lambda:sql)
    
        def during_this_period(self,s,e):
            current_time = datetime.datetime.now()
            start_str = '%s-%s-%d %s:00:00' % (current_time.year,current_time.month, current_time.day,s)
            end_str = '%s-%s-%s %d:00:00' % (current_time.year, current_time.month, current_time.day,e)
            start_time = datetime.datetime.strptime(start_str, "%Y-%m-%d %H:%M:%S")
            end_time = datetime.datetime.strptime(end_str, "%Y-%m-%d %H:%M:%S")
            return start_time, end_time
    
    class Judge(RuleHandler):
        def __init__(self,mysql_conf):
            super().__init__(mysql_conf)
        def execute(self):
            for roule in self.global_alarm_rules:
                conditions=json.loads(roule['conditions'])
                action= json.loads(roule['action'])
                self.parse_rules(conditions)()
                sql='select id,send_time,title,process_status from alarm_messages where process_status = "UNPROCESSED" %s'%(self.select_sql)
                #select id,send_time,title,process_status from alarm_messages where process_status = "UNPROCESSED"  and send_time between "2019-12-21 00:00:00" and "2019-12-21 04:00:00" and title like "%%DETECT OOM%%"
                alarm_infos=self.query(sql=sql)
                print(sql)
                print(alarm_infos)
                if alarm_infos:#符合规则的再去parse_action进行update
                    self.parse_actions(action)()
                    id_str = ','.join([str(x['id']) for x in alarm_infos])
                    sql = "update alarm_messages set %s where id in (%s)" % (self.update_sql,id_str)
                    # self.update(sql=sql)
    
    
    if __name__ == '__main__':
        judge=Judge(mysql_conf=mysql_conf)
        judge.execute()
        
    闭包的应用

     函数装饰器(实现装饰器的原理就是闭包函数)

    1、在不改变现有代码的情况下,增加函数的功能;

    2、@函数名A  =  把正下方的原始函数B,当A函数的参数传入A,并把A的return的结果,赋值给 函数B; B=return的结果 A(B)

          函数B

    无参数装饰器函数

    def auth(fun):
        def wrapper(*args,**kwargs):
            print("开始认证")
            f=fun(*args,**kwargs)
            print("结束")
        return wrapper
    @auth #@语法糖的的操作:把正下方的函数,当做一个参数,传给auth,并把index函数指向auth的的执行结果; 无参装饰器auth不执行;
    def index():
    print("主页") index()

     有参装饰器

    def auth1(name):
        def auth(fun):
            def wrapper(*args,**kwargs):
                print("%s 开始认证"% name)
                f=fun(*args,**kwargs)
                print("结束")
            return wrapper
        return auth
    
    @auth1(name='alex')  #1、 当Python解释器遇到函数名+括号auth1(name='alex'),先让auth1先执行,执行完毕,得出执行结果。
                         #2、@auth1(name='alex')的执行结果,也就是return的函数, auth函数.
                         #3、所以有参数装饰器 @是auth函数, 也就是把正下方的函数,当做一个参数,传给auth()的执行结果;wrapper函数 有参装饰器
    def index():
        print("主页")
    index()

    装饰器的缺陷

    原始函数的帮助文档会被装饰器函数覆盖,解决之道

    from functools import wraps
    def auth(func):
        @wraps(func) #使用内置函数wraps,装饰一下原始函数,会保存住原始函数的帮助信息
    from functools import wraps
    def auth(func):
        @wraps(func) #使用内置函数wraps,装饰一下原始函数,会保存住原始函数的帮助信息
        def wrapprt(*args,**kwargs):
            '''
            我是1个装饰器函数
            '''
            print('开始认证。。。')
            res=func()
            print('结束认证。。。')
            return res
        return wrapprt
    
    @auth
    def index():
        '''
        我是1个需要被装饰的函数
        '''
        print('主页')
    
    index()
    print(index.__doc__)
    View Code

     递归函数:

     递归经常和迭代一起被提到,(迭代就是从复做某事);递归:函数调用自身,每次调用自身一次,问题规模比上一次减少,最后有一个明确的结束条件

    递归就是函数执行时,调用了自己,然后把这种状态积累保存在栈内存里,遇到自己执行的结果了,一起返回出来

    吃1+吃2+吃3 函数有了执行结果 4 的时候   吐出来:吃进去的1+吃进去2+吃进去3+函数结果= 10

    堆内存:吃1+吃2+吃3,然后吐出来顺序;1------->2------->3

    栈内存:吃1+吃2+吃3,然后吐出来顺序;3------>2-------->1

    队列:吃了就拉出来,不积累;吃一个拉一个     1---->

     

    def age(n): #age()=10
        print('=========',n)
        if n==1:
            return 10
        else:
            return age(n-1)+2
    
    print(age(5))
    
    
    data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
    def seach(number,data):
        print(data)
        mid_index = int(len(data)/2)
        mid_values = data[mid_index]
        # print(data)
        if number> mid_values:
            data=data[mid_index:]
            seach(number,data)
        elif number < mid_values:
            data=data[:mid_index]
            seach(number,data)
        else:
            print('find it')
            return
    
    seach(3,data)

     执行结果:

    [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
    [1, 3, 6, 7, 9, 12, 14, 16, 17] 
    [1, 3, 6, 7]  #本程序的设计核心是 递归和二分法则:每次取出有序序列中间的那个值和要查找的number比较大于取序列的右边小于取出序列的左边,循环递归,直到找出结果;
    [1, 3]
    find it
    [1, 3]
    None

     生成器函数

    yeild 把函数的执行步骤,以yield为分界线划分成一个单位 ,遇到next(a)方法返回一个单位的执行结果1次。

    def rang2():
        star=0
        while star<100:
            yield star*4
            star+=1
    
    # for i in rang2():
    #     print(i)
    
    #生成器定义在函数里的迭代器有 yield字段
    #生成器:可以节省内存,拿一个取一个
    
    
    def rang():
        yield 1
        yield 2  #yeild 把函数的执行步骤,以yield为分界线划分成一个单位 ,遇到next(a)方法返回一个单位的执行结果1次。
        yield 3
    
    # a=rang()
    # print(next(a))
    # print(next(a))
    # print(next(a))
    
    
    def test3():
        i=0
        while i<10:
            yield "母鸡下一个鸡蛋%s"%i
            i+=1
    
    f=test3()
    f2=test3()
    # print(next(f2))
    # print(next(f2))
    # print(next(f))
    
    
    #计算 1+1+2+3+5+8的和
    def test4():
        a=1
        yield a
        b=1
        yield b
        while True:
            c=a+b
            yield c
            a=b
            b=c
    
    sum1=test4()
    
    for i in sum1:
        print(i)
    

    高阶函数

    接收1个函数作为参数输入,return返回1个函数,满足以上2条件其中一个都叫高阶函数。

      

  • 相关阅读:
    css之深入理解padding
    css布局大杂烩
    css深入理解margin
    css之深入理解border
    css样式画各种图形
    css Sprite雪碧图
    JVM,JRE,JDK
    JAVA 遍历数组
    JAVA 得到数组的长度
    大一对软件工程
  • 原文地址:https://www.cnblogs.com/sss4/p/6673811.html
Copyright © 2011-2022 走看看