欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python——nonlcoal关键字、装饰器(开放封闭原则、函数被装饰、最终写法)

程序员文章站 2022-04-09 14:02:32
一、nonlocal关键字 1、作用:将L与E(E中的名字需要提前定义)的名字统一 2、应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值 二、开放封闭原则 三、装饰器 四、装饰器的简化语法 五、有参有返的函数被修饰 六、装饰器的最终写法 七、登录认证案例 ......

一、nonlocal关键字

1、作用:将l与e(e中的名字需要提前定义)的名字统一

2、应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值

def outer():
    num=10
    print(num) # 输出结果为10
    def inner():
        nonlocal num
        num=20
        print(num) #输出级结果为20
    inner()
    print(num)   # 输出结果为20
def outer():
    num=0 # 必要写 是用于l与e的名字统一
    def inner():
        # 如果想被嵌套的函数中修改外部函数变量(名字)的值
        nonlocal  num # 将l与e(e中的名字需提前定义好)的名字统一
        num=10
        print(num) # 输出结果为10
    inner()
    print(num ) # 定义了nonlocal就是局部统一,输出结果为10
outer()
# print(num)#  属于全局,不能看到其值

 

二、开放封闭原则

1、原则: 不能修改被装饰对象(函数)的源代码——封闭
不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果——开放


2、定义:就是闭包(闭包的一个嘤嘤嘤场景)
把要装饰的函数作为外部函数的参数通过闭包操作返回一个替代版函数1

3、优点:丰富了原有函数的功能
提高了程序的可拓展性
1.0版本
def fn():
    print('fn run ')
fn()

版本2.0
def fn2():
    print('fn run 0')
    print('fn run1')
    print('fn run2')

修改了源代码,没有更改调用方式,对外调用方式还是原来的,
def fn():
    print('fn  run0')
    print('fn run ')
    print('fn run2')

 更改了调用方式,没有修改原功能代码块
def wrap(fn):
    print('fn run0')
    fn()
    print('fn run2')
wrap(fn)

 

三、装饰器

1、把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数
2、被装饰的函数:fn
3、外层函数:outer(func)、outer(fn)==》func=fn
4、替代版函数;return inner:原有功能加新功能
def fn():
    print('原有功能')

# 装饰器
def outer(tag):
    def inner():
        tag()
        print('新增功能')
        return inner
fn=outer(fn)
fn()

 

 案例 花瓶
def vase():
    print('插花')
 vase()

 增加一个绘画后观赏功能
 def  wrap(fn):
     vase()
     print('插花')
     print('绘画:进行观赏')
 wrap(vase)

 虽然满足了开放封闭原则,但出现了函数调用死循环

 def fn():
     vase()
     print('绘画:进行观赏')
 vase=fn()
 vase()

 了解:满足开放fengbiyuanze,且可以达到装饰器的作用:拓展功能
tag=vase  # 暴露在全局:
 def fn():
     tag()
    print('绘画:进行观赏')
 vase=fn
 vase()


 满足开放封闭原则(完美方法)
方式一
def wrap (tag):
    tag=vase
    def fn():
        tag()
        print('绘画:进行观赏')
    return  fn  # 拓展功能后的vase
vase =wrap()  # 相当于vase=fn
vase()

方式二、这个函数嵌套结构就是装饰器
def wrap (tag):
    def fn():
        tag() # 指原有的vase
        print('绘画:进行观赏')
    return  fn  # 拓展功能后的vase
vase =wrap(vase)  # 将拓展功能后的函数重新赋值给vase
vase() # 功能拓展了,且调用方式不变

 

四、装饰器的简化语法

ef outer(f):
    def inner():
        f()
        print("新增功能1")
    return inner

def wrap(f):
    def inner():
        f()
        print("新增功能2")
    return inner

@wrap  # 被装饰的顺序决定了新增功能的执行顺序
@outer  # <==> fn = outer(fn): inner
def fn():
    print("原有功能")

 

案例:

def outer (fn):
    def inner():
        fn()
        print('绘画:进行观赏')
    return  inner

def wrse (fn):
    def inner():
        fn()
        print('摆放功能')
    return  inner


@语法糖|笑笑语法

@wrse
@outer   #等于这个功能<==>vase =outer(vase)
def vase():
    print('插花')
vase()

 总结:一个函数可以被任意一个相关装饰器装饰,也可以被任意几个装饰器装饰
 注:装饰的顺序会影响新增功能的执行顺序

 

 

五、有参有返的函数被修饰

def check_usr(fn):# fn,login,inner:不同状态下的login,所以参数是统一的
    def inner(usr,pwd):
        # 在原功能上添加新功能
         if not(len(usr)>=3and usr.isalpha()):
            print('账号验证失败')
            return false
        #  原有功能
        result=fn(usr,pwd)
    # 在原功能下添加新功能
    #。。。。。()没有添加则用句号省略了
        return result
    return inner

@check_usr
def login(usr,pwd):
    if usr=='abc'and pwd=='123abc':
        print('登录成功')
        return  true
    print('登录失败')
    return  false

总结:1、login有参数,所以inner与fn都有相同参数
     2、login有返回值,所以inner与fn都有返回值

inner(usr, pwd):
res = fn(usr, pwd) # 原login的返回值
return res


login = check_usr(login) = inner

res = login('abc', '123qwe') # inner的返回值

 

 案例:

增加一个账号处理功能:3位以上英文字符或汉字

def check_usr(fn):
    def inner(usr,pwd):
        if not (len(usr)>=3 and usr.isalpha()):
            print('账号验证失败')
            return  false
        result=fn(usr,pwd)  #login
        return  result
    return  inner


增加一个密码处理功能:6位以上英文和数字
def check_pwd(fn):
    def inner(usr,pwd):
        if not (len(pwd)>=6 and pwd.isalnum()):
            print('密码验证失败')
            return  false
        return fn(usr,pwd)  #result=fn(usr,pwd)   return result
    return inner


 登录功能
@check_usr  # login=check_usr(login)=inner
def login(usr,pwd):
    if usr=='abc' and pwd=='123abc':
        print('登录成功')
    print('登录失败')
    return false


res=login('abc','123abc') # inner  用户名和密码正确输出验证成功
print(res)

 

六、装饰器的最终写法

# 装饰器的最终写法
def wrap  (fn):
    def inner(*args,**kwargs):
        print('前增功能')
        result =fn(*args,**kwargs)
        print('后增功能')
        return  result
    return  inner

@wrap
def fn1():
    print('fn1的原有功能')
@wrap
def fn2(a,b): # 有参数无值
    print('fn2的原有功能')

@wrap
def fn3():# 有返回值无参数
    print('fn2的原有功能')
    return true
@wrap
def fn4(a,*,c): #有参数有返回值
    print('fn2的原有功能')
    return true

fn1()
fn2(10,20)
fn3()
fn4(10,c=20)




案例:
 增加一个账号处理功能:3位及以上英文字符或汉字
def check_usr(fn):
    def inner(usr,pwd):
        if not(len(usr)>=3 and usr.isalpha()):
            print('账号验证失败')
            return  false
        result=fn(usr,pwd) #login
        return result
    return inner

登录功能
@check_usr
def login(usr,pwd):
    if usr=='abc'and pwd=='123abc':
        print('登录成功')
        return true
    print('登录失败')
    return false

res=login('abc','123abc')  #inner  账号密码正确打印成功
print(res)

 

带参装饰器

def outer(input_color):
    def wrap(fn):
        if input_color=='red':
            info='\033[36;41m  new action\33[0m'
        else:
            info='yellow:new action'
        def inner(*args,**kwargs):
            pass
            result=fn(*args,**kwargs)
            print(info)
            return result
        return inner
    return wrap #outer(color)=>>wrap

color=input('color:')

def func():
    print('func run')
func()

 

七、登录认证案例

is_login=false #登录状态
def login():
    usr=input('usr:')
    if not(len(usr)>=3 and usr.isalpha()):
        print('账号验证失败')
        return  false
    pwd=input('ped:')
    if usr=='abc'and pwd=='123abc':
        print('登录成功')
        is_login=true
    else:
        print('登录失败')
        is_login=false

完成一个登录状态校验的装饰器

def check_login(fn):
    def inner(*args,**kwargs):
        # 查看个人主页或销售功能前:如果没有登录需要先登录,繁殖可以进入其功能
        if is_login!=true:
            print('你未登录')
            login()
            # 查看个人主页或销售
        result=fn(*args,**kwargs)
        return  result

查看个人主页功能
@check_login
def home():
    print('个人主页')


销售功能
@check_login
def sell():
    print('可以销售')
home()