闭包
闭包就是能够读取其他函数内部变量的函数。
例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。
在本质上,闭包是将函数内部和函数外部连接起来的桥梁
#闭包
def test(number1):
# 外部函数
print("in test")
def test_in(number2):
# 内部函数
print("in test_in %d" % (number1+number2))
return test_in
test2 = test(1)
test2(99)
# 问题:初中里学过函数,例如 y=kx+b, y=ax^2 + bx + c
# 以y=kx+b为例,请计算一条线上的过个点 即 给x值 计算出y值
# 第1种
# k = 1
# b = 2
# y = k*x+b
# 缺点:如果需要多次计算,那么就的写多次y = k*x+b这样的式子
# 第2种
def line_2(k, b, x):
print(k*x+b)
line_2(1, 2, 0)
line_2(1, 2, 1)
line_2(1, 2, 2)
# 缺点:如果想要计算多次这条线上的y值,那么每次都需要传递k,b的值,麻烦
print("-"*50)
# 第3种: 全局变量
k = 1
b = 2
def line_3(x):
print(k*x+b)
line_3(0)
line_3(1)
line_3(2)
k = 11
b = 22
line_3(0)
line_3(1)
line_3(2)
# 缺点:如果要计算多条线上的y值,那么需要每次对全局变量进行修改,代码会增多,麻烦
print("-"*50)
# 第4种:缺省参数
def line_4(x, k=1, b=2):
print(k*x+b)
line_4(0)
line_4(1)
line_4(2)
line_4(0, k=11, b=22)
line_4(1, k=11, b=22)
line_4(2, k=11, b=22)
# 优点:比全局变量的方式好在:k, b是函数line_4的一部分 而不是全局变量,因为全局变量可以任意的被其他函数所修改
# 缺点:如果要计算多条线上的y值,那么需要在调用的时候进行传递参数,麻烦
print("-"*50)
# 第5种:实例对象
class Line5(object):
def __init__(self, k, b):
self.k = k
self.b = b
def __call__(self, x):
print(self.k * x + self.b)
line_5_1 = Line5(1, 2)
# 对象.方法()
# 对象()
line_5_1(0)
line_5_1(1)
line_5_1(2)
line_5_2 = Line5(11, 22)
line_5_2(0)
line_5_2(1)
line_5_2(2)
# 缺点:为了计算多条线上的y值,所以需要保存多个k, b的值,因此用了很多个实例对象, 浪费资源
print("-"*50)
# 第6种:闭包
def line_6(k, b):
def create_y(x):
print(k*x+b)
return create_y
line_6_1 = line_6(1, 2)
line_6_1(0)
line_6_1(1)
line_6_1(2)
line_6_2 = line_6(11, 22)
line_6_2(0)
line_6_2(1)
line_6_2(2)
# 思考:函数、匿名函数、闭包、对象 当做实参时 有什么区别?
# 1. 匿名函数能够完成基本的简单功能,,,传递是这个函数的引用 只有功能
# 2. 普通函数能够完成较为复杂的功能,,,传递是这个函数的引用 只有功能
# 3. 闭包能够将较为复杂的功能,,,传递是这个闭包中的函数以及数据,因此传递是功能+数据
# 4. 对象能够完成最为复杂的功能,,,传递是很多数据+很多功能,因此传递是功能+数据
修改闭包中的数据
x = 300
def test1():
x = 200
def test2():
nonlocal x
print("----1----x=%d" % x)
x = 100
print("----2----x=%d" % x)
return test2
t1 = test1()
t1()
装饰器
装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python, 看了下面的文章,保证你学会装饰器。
def yanzheng(func): #进行装饰
def inner():
print("正在验证1......")
func()
print("验证完成......")
return inner
# 开闭原则 对拓展开发 对修改关闭
# 既定功能 装饰器等同于 yanzheng(f1)
@yanzheng
def f1():
print("in f1")
f1()
装饰器实现过程
def set_func(func):
def call_func():
print("---这是权限验证1----")
print("---这是权限验证2----")
func()
return call_func
@set_func # 等价于test1 = set_func(test1)
def test1():
print("-----test1----")
# ret = set_func(test1)
# ret()
# test1 = set_func(test1)
test1()
test1()
装饰器的作用-来统计一个函数的运行时间
import time
def set_func(func):
def call_func():
start_time = time.time()
func()
stop_time = time.time()
print("alltimeis %f" % (stop_time - start_time))
return call_func
@set_func # 等价于test1 = set_func(test1)
def test1():
print("-----test1----")
for i in range(10000):
pass
# ret = set_func(test1)
# ret()
# test1 = set_func(test1)
test1()
test1()
对没有参数、没有返回值的函数进行装饰
def set_func(func):
def call_func():
print("---这是权限验证1----")
print("---这是权限验证2----")
func()
return call_func
@set_func # 等价于test1 = set_func(test1)
def test1():
print("-----test1----")
# ret = set_func(test1)
# ret()
# test1 = set_func(test1)
test1()
对有参数、无返回值的函数进行装饰
def set_func(func):
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func
@set_func # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)
test1(100)
test1(200)
# xx = set_func(test1)
通一个装饰器对多个函数进行装饰
def set_func(func):
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func
@set_func # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)
@set_func # 相当于 test2 = set_func(test2)
def test2(num):
print("-----test2----%d" % num)
test1(100)
test2(200)
装饰器在没有调用函数之前已经装饰了
def set_func(func):
print("---开始进行装饰")
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func
@set_func # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)
@set_func # 相当于 test2 = set_func(test2)
def test2(num):
print("-----test2----%d" % num)
# 装饰器在调用函数之前,已经被python解释器执行了,所以要牢记 当调用函数之前 其实已经装饰好了,尽管调用就可以了
# test1(100)
# test2(200)
对不定长参数的函数进行装饰(通用装饰器)
def set_func(func):
print("---开始进行装饰")
def call_func(*args, **kwargs):
print("---这是权限验证1----")
print("---这是权限验证2----")
# func(args, kwargs) # 不行,相当于传递了2个参数 :1个元组,1个字典
func(*args, **kwargs) # 拆包
return call_func
@set_func # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
print("-----test1----%d" % num)
print("-----test1----" , args)
print("-----test1----" , kwargs)
test1(100)
test1(100, 200)
test1(100, 200, 300, mm=100)
对带有返回值的函数进行装饰
def set_func(func):
print("---开始进行装饰")
def call_func(*args, **kwargs):
print("---这是权限验证1----")
print("---这是权限验证2----")
# func(args, kwargs) # 不行,相当于传递了2个参数 :1个元组,1个字典
return func(*args, **kwargs) # 拆包
return call_func
@set_func # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
print("-----test1----%d" % num)
print("-----test1----" , args)
print("-----test1----" , kwargs)
return "ok"
@set_func
def test2():
pass
ret = test1(100)
print(ret)
ret = test2()
print(ret)
多个装饰器对同一个函数进行装饰
def add_qx(func):
print("---开始进行装饰权限1的功能---")
def call_func(*args, **kwargs):
print("---这是权限验证1----")
return func(*args, **kwargs)
return call_func
def add_xx(func):
print("---开始进行装饰xxx的功能---")
def call_func(*args, **kwargs):
print("---这是xxx的功能----")
return func(*args, **kwargs)
return call_func
@add_qx
@add_xx
def test1():
print("------test1------")
test1()
应用:多个装饰器多同一个函数进行装饰
def set_func_1(func):
def call_func():
# "<h1>haha</h1>"
return "<h1>" + func() + "</h1>"
return call_func
def set_func_2(func):
def call_func():
return "<td>" + func() + "</td>"
return call_func
@set_func_1
@set_func_2
def get_str():
return "haha"
print(get_str())
使用类当做装饰器(了解即可)
# def set_func_1(func):
# def call_func():
# # "<h1>haha</h1>"
# return "<h1>" + func() + "</h1>"
# return call_func
class Test(object):
def __init__(self, func):
self.func = func
def __call__(self):
print("这里是装饰器添加的功能.....")
return self.func()
@Test # 相当于get_str = Test(get_str)
def get_str():
return "haha"
print(get_str())
带有参数的装饰器
def set_func(func):
def call_func(*args, **kwargs):
level = args[0]
if level == 1:
print("----权限级别1,验证----")
elif level == 2:
print("----权限级别2,验证----")
return func()
return call_func
@set_func
def test1():
print("-----test1---")
return "ok"
@set_func
def test2():
print("-----test2---")
return "ok"
# 这种方式不好:
# 1. 如果test1之前被调用了N次,那么就需要修改N个
# 2. 调用函数时,验证的级别应该是函数的开发者设定
# 而不是调用者设定
test1(1)
test2(2)
def set_level(level_num):
def set_func(func):
def call_func(*args, **kwargs):
if level_num == 1:
print("----权限级别1,验证----")
elif level_num == 2:
print("----权限级别2,验证----")
return func()
return call_func
return set_func
# 带有参数的装饰器装饰过程分为2步:
# 1. 调用set_level函数,把1当做实参
# 2. set_level返回一个装饰器的引用,即set_func
# 3. 用返回的set_func对test1函数进行装饰(装饰过程与之前一样)
@set_level(1)
def test1():
print("-----test1---")
return "ok"
@set_level(2)
def test2():
print("-----test2---")
return "ok"
test1()
test2()
静态方法和类方法
分别使用@staticmethod 和@classmethod 进行装饰
new 魔法方法
def __new__(cls,*args,**kwargs): #创建对象 不使用也会自动创建对象
return object.__new__(cls)