Python:Day7:python装饰器

什么是装饰器

器即函数

装饰即修饰,意指为其他函数添加新功能

装饰器定义:装饰器本质就是函数,作用就是为其他函数添加新功能。

装饰器要遵循的原则,遵循开放封闭原则即:

1.   不修改原函数的调用方式

2.   不修改被装饰函数的原代码

装饰器的储备知识

装饰器 = 高阶函数 + 函数嵌套 + 闭包

高阶函数

高阶函数定义:

1.  函数接收的参数是一个函数名

2.  函数的返回值是一个函数名

3.  满足上述任意一个条件都可称之为高阶函数

 1 # import time
 2 # def foo():
 3 #     time.sleep(3)
 4 #     print('你好啊林师傅')
 5 #
 6 # def test(func):
 7 #     # print(func)
 8 #     start_time=time.time()
 9 #     func()
10 #     stop_time = time.time()
11 #     print('函数运行时间是  %s' % (stop_time-start_time))
12 # # foo()
13 # test(foo)
14 
15 # def foo():
16 #     print('from the foo')
17 # def test(func):
18 #     return func
19 
20 # res=test(foo)
21 # # print(res)
22 # res()
23 
24 # foo=test(foo)
25 # # # print(res)
26 # foo()
27 
28 import time
29 def foo():
30     time.sleep(3)
31     print('来自foo')
32 
33 #不修改foo源代码
34 #不修改foo调用方式
35 
36 
37 #多运行了一次,不合格
38 # def timer(func):
39 #     start_time=time.time()
40 #     func()
41 #     stop_time = time.time()
42 #     print('函数运行时间是  %s' % (stop_time-start_time))
43 #     return func
44 # foo=timer(foo)
45 # foo()
46 
47 
48 #没有修改被修饰函数的源代码,也没有修改被修饰函数的调用方式,但是也没有为被修饰函数添加新功能
49 def timer(func):
50     start_time=time.time()
51     return func
52     stop_time = time.time()
53     print('函数运行时间是  %s' % (stop_time-start_time))
54 
55 foo=timer(foo)
56 foo()
高阶函数笔记

函数嵌套

定义:在一个函数里定义了另外一个函数。(注意不是调用是定义)

闭包

闭包:函数嵌套,内部函数使用了外部函数的变量,外层函数返回内层函数的引用。

 1 def father(auth_type):
 2     # print('from father %s' %name)
 3     def son():
 4         # name='linhaifeng_1'
 5         # print('我的爸爸是%s' %name)
 6         def grandson():
 7             print('我的爷爷是%s' %auth_type)
 8         grandson()
 9     # print(locals())
10     son()
11 # father('linhaifeng')
12 father('filedb')
嵌套及闭包

装饰器的实现

 

#装饰器框架:
def timmer(func):
    def wrapper():
        print(func)#内存地址
        func()
    return (wrapper())

那么如下我们来定义一个函数为它的运行加上时间统计:

#用装饰器实现统计运行时间功能
import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return wrapper


#定义的函数
@timmer #test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
# res=timmer(test)  #返回的是wrapper的地址     
# res()  #执行的是wrapper()                           可以执行但是改变了其调用方法

# test=timmer(test)  #返回的是wrapper的地址
# test()  #执行的是wrapper()                          将变量名res替换为test这样调用方法也改过来了

#  @timmer  就相当于 test=timmer(test)                @timmer在哪个函数前面就指定了哪个函数需要用此装饰器功能
test()                                              #运行方式、源代码均未改变,并且为其加上了新功能
-------------------------------------------------------------------------------------------------------
问题1
那么接下来假如test()有返回值该怎么处理呢?
def test():
    time.sleep(3)
    print('test函数运行完毕')
res= test()
print(res)
>>>输出None 没有返回值默认返回None
-------------------------------------------------------------------------------------------------------
改良1
@timmer
def test(): time.sleep(3) print('test函数运行完毕')
return '这是test的返回值'
res = test()
print(res)

import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        res = func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return res

-------------------------------------------------------------------------------------------------------
问题2
那么test有参数呢?
def test(*args, **kwargs):
    time.sleep(3)
    print('test函数运行完毕')
res= test()
print(res) #如此一运行就报错

-------------------------------------------------------------------------------------------------------
改良2
import time
def timmer(func): #func=test1
def wrapper(*args,**kwargs): #test('linhaifeng',age=18) args=('linhaifeng') kwargs={'age':18}
start_time=time.time()
res=func(*args,**kwargs) #就是在运行test() func(*('linhaifeng'),**{'age':18})
stop_time = time.time()
print('运行时间是%s' %(stop_time-start_time))
return res
return wrapper

# @timmer #test=timmer(test)
def test(name,age):#两个参数
time.sleep(3)
print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age))
return '这是test的返回值'

@timmer
def test1(name,age,gender):#多个参数
time.sleep(1)
print('test1函数运行完毕,名字是【%s】 年龄是【%s】 性别【%s】' %(name,age,gender))
return '这是test的返回值'

# res=test('linhaifeng',age=18) #就是在运行wrapper
# # print(res)
# test1('alex',18,'male')

test1('alex',18,'male')

 例题:验证功能、选择认证类型装饰器(假京东)

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}

def auth(auth_type='filedb'):
    def auth_func(func):
        def wrapper(*args,**kwargs):
            print('认证类型是',auth_type)
            if auth_type == 'filedb':
                if current_dic['username'] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username=input('用户名:').strip()
                passwd=input('密码:').strip()
                for user_dic in user_list:
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_dic['username']=username
                        current_dic['login']=True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('用户名或者密码错误')
            elif auth_type == 'ldap':
                print('鬼才特么会玩')
                res = func(*args, **kwargs)
                return res
            else:
                print('鬼才知道你用的什么认证方式')
                res = func(*args, **kwargs)
                return res

        return wrapper
    return auth_func

@auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type  --->index=auth_func(index)
def index():
    print('欢迎来到京东主页')

@auth(auth_type='ldap')
def home(name):
    print('欢迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

# print('before-->',current_dic)
# index()
# print('after--->',current_dic)
# home('产品经理')
shopping_car('产品经理')

作业:完成对haproxy文件的增删改查

 

 1 1、查
 2     输入:www.oldboy.org
 3     获取当前backend下的所有记录
 4 
 5 2、新建
 6     输入:
 7         arg = {
 8             'bakend': 'www.oldboy.org',
 9             'record':{
10                 'server': '100.1.7.9',
11                 'weight': 20,
12                 'maxconn': 30
13             }
14         }
15 
16 3、删除
17     输入:
18         arg = {
19             'bakend': 'www.oldboy.org',
20             'record':{
21                 'server': '100.1.7.9',
22                 'weight': 20,
23                 'maxconn': 30
24             }
25         }
需求

 

 1 global
 2         log 127.0.0.1 local2
 3         daemon
 4         maxconn 256
 5         log 127.0.0.1 local2 info
 6 defaults
 7         log global
 8         mode http
 9         timeout connect 5000ms
10         timeout client 50000ms
11         timeout server 50000ms
12         option  dontlognull
13 
14 listen stats :8888
15         stats enable
16         stats uri       /admin
17         stats auth      admin:1234
18 
19 frontend oldboy.org
20         bind 0.0.0.0:80
21         option httplog
22         option httpclose
23         option  forwardfor
24         log global
25         acl www hdr_reg(host) -i www.oldboy.org
26         use_backend www.oldboy.org if www
27 
28 backend www.oldboy1.org
29         server 101.1000.7.9 101.1000.7.9 weight 20 maxconn 30
30         server 2.2.2.7 2.2.2.7 weight 30 maxconn 4000
31         server 10.10.10.1 10.10.10.1 weight 22 maxconn 2000
32         server 2.2.2.5 2.2.2.5 weight 30 maxconn 4000
33 
34 backend www.oldboy2.org
35         server 3.3.3.3 3.3.3.3 weight 20 maxconn 3000
36 backend www.oldboy20.org
37         server 10.10.0.10 10.10.0.10 weight 9999 maxconn 33333333333
haproxy配置文件

 

通过该作业应该掌握的知识:

1、函数

2、文件处理

3、tag用法

4、程序的解耦

在构建一个程序项目之前,首先需要设计程序的框架,从总体上构建一个项目中的一个个功能,之后对每一个功能进行补充,最终实现总体的功能。

1 程序的总体框架:
首先把所有的功能设计成相应的函数,用pass来实现。

def add(operation):
    "增加"
    pass

def remove(operation):
    "删除"
    pass

def change(operation):
    "更改"
    pass



if __name__ == '__main__':
    msg ="""
    1.查找
    2.增加
    3.删除
    4.更改
    5.退出
    """
    # 通过定义字典,在输入序号时,能够对应相应的函数
    msg_dict={
        "1":serach,
        "2":add,
        "3":remove,
        "4":change,
        "5":exit
    }

    while True:
        print(msg)
        usr_choice = input("请输入要进行的操作>>:").strip()
        if len(usr_choice) == 0 or usr_choice not in msg_dict : continue  # 用户输入为空,或者超出字典的内容,继续输入
        if usr_choice == '5':
            break

        operation = input("请输入要操作的内容>>:").strip()

        msg_dict[usr_choice](operation)  # 通过字典调用函数,并传入要查询的参数operation
1.1 查询函数实现

查找是首先匹配到相应的行,判断开始和结束的位置,这里是通过标志位进行控制的。

def serach(operation):
    "查找"
    # pass
    # serach_line = "backend %s" % operation   # 查找的内容之情有backend,把输入的内容和backend进行拼接
                                             # 还可以通过if line.strip().startwith("backend") and operation in line
    search_list =[]     # 将查找到的内容存放到此列表中
    search_flag = False  # 定义一个flag读取到匹配行时打开此flag
    with open("haproxy.conf",encoding="utf-8") as f_read:   # 打开文件,默认读操作
        for line in f_read: # 逐行读取文件
            # if line.strip() == serach_line:    # 将匹配到每一行去掉换行,
            if line.strip().startswith("backend") and operation in line:  # 匹配到相应的行
                search_flag = True             # 匹配到后标志位为True
                continue                       # 跳过匹配的行,操作的是下一行的内容
            if line.strip().startswith("backend") and search_flag:   # 判断结束行,需要放在search_flag之前
                break
                # search_flag = False
            if search_flag:
                search_list.append(line.strip())       # 将匹配的内容存储到列表中,同时删除换行符
        for i in search_list:
            print(i)
    return search_list      # 返回值是获取到的内容的列表
1.2 文件内容的增加操作

对文件的增加操作涉及了输入一个字典内容,但是实际在输入的过程中,输入的是字符串,这里用到eval()函数,能够将输入的字典形式的内容转换成字典的格式。

对文件进行修改,必然会创建一个新的文件。在这里采用的是把原来的文件中内容一行行读取并写入到新的文件中,最后把新文件的名字改成原来文件的名字。

def add(operation):
    "增加,增加内容存在的情况(可以通过search()函数进行查询),增加内容不存在的情况"
    # pass
    backend_url = operation["backend"]  # 获取输入的字典中的backend的value
    record_list = serach(backend_url)   #将获取到的url传递给search函数,search函数的返回值是search_list[],并赋值
    backend_data = "backend %s" %backend_url  # 将获取的URL同backend进行字符串的拼接
                                              # 组成 backend www.oldboyX.org

    # 用户输入的内容格式:
    # {"backend":"www.oldboy.org","record":{"server":"1.1.1.1","weight":"3000","maxconn":"33333"}}
    # 获取输入的字典的内容并进行字符串的拼接
    dict_string = "sever %s weight %s maxconn %s" %(operation["record"]["server"],\
                                                    operation["record"]["weight"],\
                                                    operation["record"]["maxconn"],
                                                    )
    if not record_list:  # 这是record_list中不存在查询的内容的情况,需要进行写入
        record_list.append(backend_data)    # 首先对record_list进行添加  backend www.oldboyX.org
        record_list.append(dict_string)                # 添加具体的server weight  maxconn  信息
        with open("haproxy.conf",encoding="utf-8") as file_read,\
                open("haproxy_new.conf","w+",encoding="utf-8") as file_write:
                                  # 读取源文件的内容写入到新的文件中,并写入添加的内容
            for line_read in file_read:    # 遍历源文件的每一行内容
                file_write.write(line_read)   # 逐行写入新的文件

            for new_line in record_list:
                if new_line.startswith("backend"):    # 判断新的内容是backend时,写入并换行
                    file_write.write(new_line+"\n")
                else:
                    file_write.write("%s%s\n" %(" "*8,new_line))
        import os
        os.rename("haproxy.conf","haproxy_bak.conf")   # 将源文件备份
        os.rename("haproxy_new.conf","haproxy.conf")   # 将新文件重命名
1.3 文件内容的删除操作

文件删除是在文件内容查询的基础进行修改的

def remove(operation):
    "删除"
    # pass
    backend_url = operation["backend"]  # 获取输入的字典中的backend的value
    record_list = serach(backend_url)  # 将获取到的url传递给search函数,search函数的返回值是search_list[],并赋值
    backend_data = "backend %s" % backend_url  # 将获取的URL同backend进行字符串的拼接
    # 组成 backend www.oldboyX.org

    # 用户输入的内容格式:
    # 删除以下的内容
    # {"backend":"www.oldboy20.org","record":{"server":'10.10.0.10.10.10.0.10',"weight":9999,"maxconn":333}}
    # 获取输入的字典的内容并进行字符串的拼接
    dict_string = "sever %s weight %s maxconn %s" % (operation["record"]["server"], \
                                                     operation["record"]["weight"], \
                                                     operation["record"]["maxconn"],
                                                     )
    if not record_list :  # 没有backend的情况 和 有backend 但是下面的内容不存在的情况
        print("没有需要删除的内容")
        return
    else:
        record_list.insert(0,backend_data)  # 把拼接的backend信息插入到list中

        with open("haproxy.conf",encoding="utf-8") as file_read,\
                open("haproxy_new.conf","w+",encoding="utf-8") as file_write:
                                 # 读取源文件的内容写入到新的文件中,并写入添加的内容
            tag = False
            flag_write = False
            for r_line in file_read:
                if r_line == backend_data:
                    tag = True
                    continue
                if tag and r_line.startswith("backend"):
                    tag = False
                if not tag:
                    file_write.write(r_line)
                else:
                    if not flag_write:
                        for new_line in record_list:
                            if new_line.startswith("backend"):
                                file_write.write(new_line+"\n")
                            else:
                                file_write.write("%s%s\n" % (" " * 8, new_line))


        os.rename("haproxy.conf", "haproxy_bak.conf")  # 将源文件备份
        os.rename("haproxy_new.conf", "haproxy.conf")  # 将新文件重命名
1.4 文件内容的修改

 

你现在所遭遇的每一个不幸,都来自一个不肯努力的曾经!

                                                                                                                                                                              Victor

posted @ 2018-07-10 16:32  毛丫头  阅读(137)  评论(0)    收藏  举报