前言:

函数在编程中有着至关重要的地位,它组织代码、使代码复用,下面我们将分类介绍一下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条件其中一个都叫高阶函数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

posted on 2017-04-06 15:46  Martin8866  阅读(330)  评论(0编辑  收藏  举报