python高级——闭包和装饰器

python高级

函数传递

函数也可以作为参数传递
python中都是对地址进行传递的,所以函数名中存放的是函数所在的空间地址
函数名()才是调用函数,执行函数中的代码
所以函数可以像普通变量一样传递,也可以作为参数使用
函数作为参数传递的例子:

def A():
    print('我是A')
def B(fun):
    print('我是B,我要调用参数的函数')
    fun()
if __name__ == '__main__':
    B(A)

闭包

概念

  1. 函数嵌套
  2. 内部函数使用了外部函数的变量
    3.外部函数返回了内部函数
    我们把满足上面三个条件的内部函数称为闭包
    自定义闭包例子:
def fun_out(num1):
    def fun_inner(num2):
        return num1+num2
    print(num1)  # 1
    return fun_inner
if __name__ == '__main__':
    fi = fun_out(1)
    print(fi(2))  # 3

内部函数修改外部函数的变量

使用关键字nonlocal可以修改外部函数的变量,如果不使用该关键字直接修改则是重新定义了一个同名变量
例子:

def fun_out(num1):
    def fun_inner(num2):
      '''如果这样写在外部函数打印的number还是1,因为这里只是新定义了一个内部变量而不是对外部变量进行修改'''
        num1 = 23
        return num1+num2
    fun_inner(2)
    print(num1)  # 1
    return fun_inner
if __name__ == '__main__':
    fi = fun_out(1)
    print(fi(2))  # 23
——————————————————————————————————
def fun_out(num1):
    def fun_inner(num2):
        nonlocal num1
        num1 = 23
        return num1+num2
    fun_inner(2)
    print(num1)  # 1
    return fun_inner
if __name__ == '__main__':
    fi = fun_out(1)

装饰器

装饰器的作用

装饰器是在不改变原有函数源代码的情况下,给已有函数添加新的功能
装饰器本质上是一个闭包函数,外部函数传递函数,供内部函数调用
可以在原有函数上方通过@装饰器名字使用装饰器
在原有函数名的上方写@装饰器等同于fun_out(fun)()

无参装饰器

def fun_out(fun):
    def fun_inner():
        print('登陆')
        fun()
    return fun_inner
@fun_out
def fun():
    print('开始发布')
if __name__ == '__main__':
    fun()

装饰器装饰带参数的函数

内部函数的参数要和被装饰函数的参数保持一致

def fun_out(fun):
    def fun_inner(name):
        print('登陆')
        fun(name)
    return fun_inner
@fun_out
def fun(name):
    print('%s开始发布'%name)

if __name__ == '__main__':
    fun('zhangsan')

被装饰的函数带返回值

内部函数带返回值,返回被装饰函数的返回值

    def fun_inner(name):
        print('登陆')
        return fun(name)
    return fun_inner
@fun_out
def fun(name):
    print('%s开始发布'%name)
    return name

if __name__ == '__main__':
    print(fun('zhangsan'))

不定长参数

装饰器可以供多个函数自定义使用,装饰器的内部函数定义不定长参数,被装饰函数随机传参

def fun_out(fun):
    def fun_inner(*args,**kwrags):
        print('登陆')
        return fun(*args,**kwrags)
    return fun_inner
@fun_out
def fun(name):
    print('%s开始发布'%name)
    return name
@fun_out
def make(addr):
    print('发布于%s'%addr)
    return addr
if __name__ == '__main__':
    print(fun('zhangsan'))
    print(make('beijing'))
    '''
    登陆
    zhangsan开始发布
    zhangsan
    登陆
    发布于beijing
    beijing
    '''

多个装饰器装饰一个函数

多个装饰器作为多行写在函数名上方即可。离被装饰函数最近的那个装饰器先装饰函数

def fun_out1(fun):
    def fun_inner1(*args,**kwrags):
        print('登陆校验1')
        return fun(*args,**kwrags)
    return fun_inner1
def fun_out2(fun):
    def fun_inner2(*args,**kwrags):
        print('登陆校验2')
        return fun(*args,**kwrags)

    return fun_inner2
@fun_out2
@fun_out1
def fun(name):
    print('%s开始发布'%name)
    return name
if __name__ == '__main__':
    fun('zhangsan')
    '''
    登陆校验2
    登陆校验1
    zhangsan开始发布
    '''

带有参数的装饰器

装饰器的外部函数只能有一个参数,必须是被装饰的那个函数
通过在装饰器的外层再封装一层函数来实现传递参数,此时在使用@装饰器名(参数)来修饰函数时,第一步执行的是装饰器名(参数)得到内层装饰器后再装饰函数

def logging(flag):
    def fun_out(fun):
        def fun_inner(*args,**kwargs):
            if flag == '+':
                print('这是加法运算')
            elif flag == '-':
                print('这是剑法运算')
            else:
                print('只支持加减法运算')
            return fun(*args,**kwargs)
        return fun_inner
    return fun_out
@logging('+')
def fun(a,b):
    return a+b
if __name__ == '__main__':
    print(fun(1,4))

类装饰器

_call_魔术方法

如果类中定义了_call_魔术方法,那么这个类就可以像函数一样被调用了
将装饰器要装饰部分写在_call_中即可以实现类装饰器的功能

类定义部分:
class Dog():
    length = 50
    # 胖了多少斤
    set_height = -1
    def __init__(self,name,age,color,length):
        self.name = name
        self.age = age
        self.color = color
        self.length = length
    def __call__(self, *args, **kwargs):
        return '叮咚,调用了callable函数,使对象能像函数一样调用'
调用部分:
if __name__ == '__main__':
    # print(fun(1,4))
    jelly = Dog('果冻', '7个月了', 'white', 15)
    print(jelly())  # 叮咚,调用了callable函数,使对象能像函数一样调用

property属性

property属性是负责把类中的一个方法当作属性使用

装饰器方式使用

  1. 使用@property修饰获取属性的方法
  2. 使用@方法名.setter修饰设置属性的方法【这里的方法名为获取属性方法的方法名】
    调用时直接对象.获取属性的方法名不用加括号即可获取属性,对象.设置属性的方法名不用加括号=新的值即可更改原有值
类定义部分:
class Father:
   name = 'zhangsan'
   age = 20
   money = 500000
   __dono = '这是我自己的'
   small = '这是可以继承的属性'
   def __init__(self,name,age,money):
       self.name = name
       self.age = age
       self.money = money
   @property
   def get_done(self):
       return self.__dono
   @get_done.setter
   def set_done(self,dono):
       self.__dono = dono
调用部分:
if __name__ == '__main__':
   zhangsan = Father('zhangsan',45,5000000)
   print(zhangsan.get_done)  # 这是我自己的
   zhangsan.set_done = '改了'
   print(zhangsan.get_done)  # 改了

类属性方式使用

定义:类属性名 = property(获取值的方法名,设置值的方法名)
使用:对象.类属性名
对象.类属性名 = 值

类定义部分:
class Father:
    name = 'zhangsan'
    age = 20
    money = 500000
    __dono = '这是我自己的'
    small = '这是可以继承的属性'
    def __init__(self,name,age,money):
        self.name = name
        self.age = age
        self.money = money
    # @property
    def get_done(self):
        return self.__dono
    # @get_done.setter
    def set_done(self,dono):
        self.__dono = dono
    # 类属性的方式将方法当成属性调用
    done = property(get_done,set_done )
调用部分:
if __name__ == '__main__':
    zhangsan = Father('zhangsan',45,5000000)
    print(zhangsan.done)  # 这是我自己的
    zhangsan.done = '改了'
    print(zhangsan.done)  # 改了

with语句和上下文管理器

with语句

文件操作时使用with语句可以自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。使得读写文件更加安全
文件使用完后如果不关闭,文件对象会一直占用操作系统的资源,并且操作系统同一时间能打开的文件数量是有限的,如果到达极限则不能打开新的文件
语法:
with 表达式 as 别名:
代码块
例如:

with open('test.txt','r') as f:
    f.read()

上下文管理器

with的安全性是靠上下文管理器来实现的,with创建的f文件对象就是一个上下文管理器对象
由下图可以看到,f对象实现了_enter_和_exit_方法

image.png

一个类只要实现了_enter_和_exit_方法,通过该类创建的对象,我们就称为上下文管理器
例子:

import time
class File:
    def __init__(self,file_name,file_model):
        self.file_name = file_name
        self.file_model = file_model

    # 上文方法
    def __enter__(self):
        print('这是上文')
        self.file = open(self.file_name,self.file_model)
        return self.file
    # 下文方法
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('这是下文')
        self.file.close()
if __name__ == '__main__':
    with File('test.txt','r') as f:
        while True:
            line = f.readline()
            time.sleep(5)
            if not line:
                break
            print(line)

在程序执行过程中我点击停止执行后在打印报错前将下文方法中的内容执行了


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • 1.魔法方法__call__() 让类的实例化对象可以像函数一样被调用 2.闭包 在函数内部再定义一个函数,并且内...
    pandarking阅读 158评论 0 0
  • 闭包和装饰器 1.8 闭包和装饰器 学习目标 1. 能够说出闭包的定义形式 2. 能够说出装饰器的实现形式 ...
    Cestine阅读 531评论 0 0
  • 1.1装饰器 装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中...
    PythonMaO阅读 470评论 1 5
  • 1.装饰器的理解 装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面...
    一只写程序的猿阅读 862评论 3 22
  • 1.1==,is的使用 ·is是比较两个引用是否指向了同一个对象(引用比较)。 ·==是比较两个对象是否相等。 1...
    TENG书阅读 721评论 0 0