在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
示例
def outer(logo):
def inner(msg):
#logo="<"+logo+">" 会报错 表示不认识 logo
nonlocal logo #如果要修改 外部函数的值必须使用nonlocal修饰
logo="<"+logo+">"
#print(f"<{logo}>{msg}<{logo}>")
print(f"{logo}{msg}{logo}")
return inner
fn=outer("mytest")
fn("你好") #<mytest>你好<mytest>
需要使用nonlocal关键字修饰外部函数的变量才可在内部函数中修改它
优点,使用闭包可以让我们得到:
无需定义全局变量即可实现通过函数,持续的访问、修改某个值
闭包使用的变量的所用于在函数内,难以被错误的调用修改
缺点:
由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
装饰器其实也是一种闭包, 其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
如我们希望给sleep函数,增加一个功能:
在调用sleep前输出:我要睡觉了
在调用sleep后输出:我起床了
def sleep():
import random
import time
print("睡眠中.....")
time.sleep(random.randint(1,3))
sleep()
可以借助闭包的功能
定义一个闭包函数, 在闭包函数内部:
执行目标函数
同时添加想要的功能
def sleep():
import random
import time
print("睡眠中.....")
time.sleep(random.randint(1,3))
def outer(func):
def inner():
#print(f"<{logo}>{msg}<{logo}>")
print(f"我要睡觉了...")
func()
print(f"我要起床了...")
return inner
fn = outer(sleep)
fn()
装饰器的语法糖:可以使用注解的方式来使用闭包
def outer2(func):
def inner2():
#print(f"<{logo}>{msg}<{logo}>")
print(f"我要睡觉了...")
func()
print(f"我要起床了...")
return inner2
@outer2 # 增加注解
def sleep():
import random
import time
print("睡眠中.....")
time.sleep(random.randint(1,3))
sleep()
设计模式是一种编程套路,可以极大的方便程序的开发。
最常见、最经典的设计模式,就是我们所学习的面向对象了。
除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模式:
单例、工厂模式、 建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式等等模式
这里我挑选了2个经常用到的单例、工厂模式进行了解。
单例模式
某些场景下, 我们需要一个类无论获取多少次类对象,都仅仅提供一个具体的实例
用以节省创建类对象的开销和内存开销
比如某些工具类,仅需要1个实例,即可在各处使用,这就是单例模式所要实现的效果
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点
适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它时。
实现方式:
1.在一个文件中定义类并创建对象
class StrUtil:
pass
str_util = StrUtil()
2.另一个文件中直接导入对象使用
from imp_file import str_util
sutil1 = str_util
sutil2 = str_util
print(sutil2)#<imp_file.StrUtil object at 0x000001A13030A050>
print(sutil1)#<imp_file.StrUtil object at 0x000001A13030A050>
工厂模式
当需要大量创建一个类的实例的时候, 可以使用工厂模式。
即,基于工厂提供的方法去创建对象,可以太容易控制对象创建逻辑。
一般情况下创建对象:
class Person:
pass
class Worker(Person):
pass
class Student(Person):
pass
class Teacher(Person):
pass
worker = Worker()
stu = Student()
teacher = Teacher()
工厂模式创建对象:
class Person:
pass
class Worker(Person):
pass
class Student(Person):
pass
class Teacher(Person):
pass
class Factory:
def get_person(self,p_type):
if p_type=='w':
return Worker()
if p_type=='s':
return Student()
else:
return Teacher()
factory = Factory()
worker = factory.get_person('w' )
stu = factory.get_person('s')
teacher = factory.get_person('t')
使用工厂类的get_person()方法去创建具体的类对象
优点:
大批量创建对象的时候有统一的入口,易于代码维护,当需要修改创建逻辑时,仅修改工厂类的创建方法即可
符合现实世界的模式,即由工厂来制作产品(对象)