一、闭包

1、什么是闭包

a、必须有内嵌函数
b、内部函数引用外部函数的变量
c、外部函数的返回值是内部函数

# 内部函数inner()在这就是一个闭包函数
# outer函数嵌套inner函数
# inner函数使用变量a和b
# outer函数的返回值是inner
def outer(a):
    b = 10
    def inner():
        #参数a和变量b都成inner函数的私有变量
        print(a+b)

    return inner

f = outer(5)  # f相当于inner
a = 7
f()        # f()相当于inner()
# 输出的结果是15

2、闭包的作用:

保存外部函数的变量,不会随着外部函数调用完而销毁
上面的例子变量a和b不会随着outer函数的调用完而销毁,所以后面即使将a赋值为7,输出的结果还是15

二、装饰器

装饰器的本质是闭包,在不改变函数或类的源代码基础上,添加额外功能
给函数使用两个装饰器,执行顺序是由里向外执行

1、函数装饰器

1.1、不带参数的装饰器

a、给函数增加计时功能的装饰器

import time

def runtime(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(f"函数执行用时{end - start}s")
    return inner

@runtime  
#  @runtime 相当于set_time= runtime(set_time)
def set_time():
    time.sleep(10)

set_time()
# 输出:函数执行用时10.012602090835571s

b、给函数增加日志功能

def log(func):
    def inner():
        print(f"函数是{func.__name__}")
    return inner

@log
def add():
    a = 6
    b = 99
    return a+b

add()
#输出:函数是add

1.2、带参数的装饰器

import time
def user(name):
    def log(func):
        def inner():
            start = time.time()
            func()
            end = time.time()
            print(f"{name}使用函数{func.__name__}执行用时{end - start}s")

        return inner
    return log
@user(name="张三")
def func():
    a = 6
    b = 99
    return a + b
func()
# 输出:张三使用函数func执行用时0.0s

2、类装饰器

Python还提供了类装饰器与@staticmethod,@classmethod,@property面向对象编程中常用的装饰器
• staticmethod:把类中定义的实例方法变成静态方法
• classmethod:把类中定义的实例方法变成类方法
• property:把类中定义的实例方法变成类属性。

2.1、写一个计时功能的类装饰器

1、不带参数

import time

class Runtime:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start = time.time()
        self.func()
        end = time.time()
        print(f"函数执行用时{end - start}s")

@Runtime
def f():
    time.sleep(5)

f()
# 输出:函数执行用时5.004265785217285s

2、带参数

import time

class Runtime:
    def __init__(self, func):
        self.func = func

    def __call__(self,t, *args, **kwargs):
        start = time.time()
        self.func(t)
        end = time.time()
        print(f"函数执行用时{end - start}s")

@Runtime
def f(t):
    time.sleep(t)

f(6)
#输出:函数执行用时6.008318901062012s

2.2@property应用

@property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。可定义只读属性就是写保护,也就是真正意义上实现私有属性(属性前双下划线)可以访问的。

class Person(object):
    def __init__(self, name):
        self.name = name
        self.__age = 15

    @property
    def age(self):
        return self.__age


zs = Person('zhangsan')  
print(zs.age)  # 结果为15
zs.age = 18  # 报错无法给年龄赋值

因为@property将age函数变成age属性,间接访问__age__,并且对age有写保护,所以zs.age赋值时报错。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐