# Python **Repository Path**: code-player-sliu/python ## Basic Information - **Project Name**: Python - **Description**: python 相关知识 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-20 - **Last Updated**: 2023-11-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1. 闭包 - **闭包函数**:在嵌套函数中,外函数必须返回内函数的引用,内函数必须引用外函数中的变量,但不一定要有返回。比如: ```python def outer(a): # 条件1:嵌套函数 b = 1 def inner(x): return a * x + b # 条件2:内函数引用外函数中的变量, return inner # 条件3:外函数返回内函数的引用 line_A = outer(2) # y=2x+1 line_B = outer(3) # y=3x+1 print(line_A(2)) # 5 print(line_B(3)) # 10 ``` - **查看“闭包”**: - 闭包函数:__closure__ 属性返回一个包含了闭包引用的外部变量的一个元组对象; - 非闭包函数:__closure__ 属性返回None。 ```python print(line_A.__closure__) # 输出:(, ) for i in line_A.__closure__: # 打印引用的外部变量值 print(i.cell_contents) # 输出 2、1 ``` - **为什么叫闭包**:闭包在被返回时,它的所有变量就已经固定,形成了一个封闭的对象,这个对象包含了其引用的所有外部、内部变量和表达式,闭包参数除外。如下: ```python def line_conf(a): b = 1 def line(x): return a * x + b return line line_A = line_conf(2) b = 20 print(line_A(1)) # 3 ``` - **用途**: - 闭包是实现面向对象的一种方法,外函数中的变量好比类属性,内函数好比类方法。当对象中只有一个方法时,使用闭包更好; - 闭包让外层函数内的变量常驻在内存中,该功能可以用于实现单利模式; - 外函数返回内函数并将其赋值给一个变量,因此,其内存空间不会被释放; - 而内函数又在其函数体内引用了外函数的变量,导致该变量也不会被回收。 - 可用于实现装饰器。其中: - 外函数就是装饰器函数,接受被装饰的函数作为参数,并返回内函数; - 内函数实现具体的装饰器功能,并返回传入的函数调用。 - **内存消耗**:闭包使函数中的变量都被保存在内存中,会增加内存消耗,避免滥用; # 2. 装饰器 - **装饰器**:在不改变函数结构和调用方式基础上,为其增加新的功能,符合对扩展开放、对修改封闭原则(开放封闭原则)。具体实现: - 在嵌套函数中, - 外函数就是装饰器函数,接受被装饰的函数作为参数,并返回内层函数; - 最内层函数实现具体的装饰器功能,并返回传入的参数函数调用结果。 - **简单装饰器**: ```python import time def baiyu(): print("我是攻城狮白玉") time.sleep(2) def count_time(func): def wrapper(): t1 = time.time() result = func() print("执行时间为:", time.time() - t1) return result return wrapper if __name__ == '__main__': # 因为装饰器count_time(baiyu)返回的是函数对象 wrapper,这条语句相当于 baiyu = wrapper baiyu = count_time(baiyu) # 执行baiyu()就相当于执行wrapper() baiyu() ``` - **函数装饰器**: - **装饰器语法糖@**:@count_time默认传入的参数就是被装饰的函数blog。 ```python import time def count_time(func): def wrapper(*args, **kwargs): # 内函数带参数 t1 = time.time() func(*args, **kwargs) # 具体执行时带参数 print("执行时间为:", time.time() - t1) return wrapper @count_time def blog(name): print('进入blog函数', name) if __name__ == '__main__': blog('刘帅') ``` - **装饰器带参数**: ```python import time def count_time_args(msg=None): def count_time(func): def wrapper(*args, **kwargs): t1 = time.time() func(*args, **kwargs) print(f"[{msg}]执行时间为:", time.time() - t1) return wrapper return count_time @count_time_args(msg="baiyu") def fun_one(): time.sleep(1) @count_time_args(msg="zhh") def fun_two(): time.sleep(1) if __name__ == '__main__': fun_one() fun_two() ``` - **类装饰器**:带参数和不带参数的类装饰器参数的位置和被修饰函数的传参位置不一样。 - **类装饰器**: ```python import time class BaiyuDecorator: def __init__(self, func): self.func = func print("执行类的__init__方法") def __call__(self, *args, **kwargs): print('通过__call__()方法调用真正的装饰方法') t1 = time.time() result = self.func(*args, **kwargs) print("执行时间为:", time.time() - t1) return result @BaiyuDecorator def baiyu(): print("我是攻城狮白玉") time.sleep(2) return '返回值' if __name__ == '__main__': res = baiyu() print(res) ``` - **带参数的类装饰器**: ```python class BaiyuDecorator: def __init__(self, arg1, arg2): """ 传入装饰器的参数 """ print('执行类Decorator的__init__()方法') self.arg1 = arg1 self.arg2 = arg2 def __call__(self, func): """ 因为装饰器带了参数,所以接收传入函数变量的位置是这里 """ print('执行类Decorator的__call__()方法') def baiyu_warp(*args): print('执行wrap()') print('装饰器参数:', self.arg1, self.arg2) print('执行' + func.__name__ + '()') func(*args) print(func.__name__ + '()执行完毕') return baiyu_warp @BaiyuDecorator('Hello', 'Baiyu') def example(a1, a2, a3): print('传入example()的参数:', a1, a2, a3) if __name__ == '__main__': print('准备调用example()') example('Baiyu', 'Happy', 'Coder') print('测试代码执行完毕') ``` - **装饰器的嵌套**:对某个被装饰函数,增加多个功能。在执行的时候先执行原函数的功能,然后再**由里到外**依次执行装饰器的内容。 ```python @BaiyuDecorator_1 # 最后执行 @BaiyuDecorator_2 # 然后执行 @BaiyuDecorator_3 # 再执行 def baiyu(): print("我是攻城狮白玉") # 先执行 if __name__ == '__main__': baiyu() ``` - **用途**:较多函数都需要一个新功能,希望一处实现,多处复用,比如:统计函数执行时间。 - **装饰器 VS 闭包**: - 装饰器本质是一个闭包; - 都利用了Python函数既可以嵌套、又可以接受函数参数、又可以返回一个函数的特点; - 闭包偏向于利用内存常驻的特点,而装饰器偏向于利用函数返回函数的特点。 # 3. 魔法函数 - `__call__()`:实现该方法的类可以使该类的实例像函数一样被调用。 ```python class BaiyuDecorator: def __init__(self, arg1, arg2): self.arg1 = arg1 self.arg2 = arg2 def __call__(self, name): print(name) return name if __name__ == '__main__': baiyu = BaiyuDecorator('Happy', 'Coder') baiyu.__call__() baiyu('百度') # 因为类实现了__call__方法。因此,类变成了可调用对象,否则报错。 print(callable(baiyu)) # 使用callable()方法可以判断某对象是否可以被调用 ``` - `__new__() 和 __init__()`: - 类的实例化包含两个步骤: ```python class CapStr(str): def __new__(cls, string): # 第一个参数必须是类对象cls self_init = super().__new__(cls, string) # 必须返回实例化出来的实例对象 print('首先被调用!实例化对象分配内存地址:',id(self_init)) # 2691640428616 return self_in_init def __init__(self, string): """ __new__返回的实例化对象对应参数self """ print("分配的内容地址:", id(self)) # 2691640428616 if __name__ == "__main__": a = CapStr("I love China!") print(id(a)) # 2691640428616 ``` - **创建对象**: `__new__` 函数负责在内存中开辟内存空间存放类的实例; - **初始化对象**: `__init__` 函数负责给实例的属性赋予初始值。 - **new VS init**: - `__new__` 既能开辟内存空间也能对实例的属性进行初始化; `__init__` 只能对实例的属性进行初始化,不能开辟内存空间。 - 两个函数除第一个输入参数外,其他输入参数都相同 # 4. 单例模式 - **定义**:保证类只会生成一个实例。比如:数据库的访问,避免重复读写数据库。 - 单例类创建自己的唯一实例对象,并且在全局都可以访问该对象; - 全局变量也可以实现该效果,但代码量大时,程序比较混乱、变量可能重名或被执行一些操作。 - **优缺点**: - **优点**:内存里只有一个实例,减少了内存的开销, 避免频繁的创建和销毁对象,可以提高性能, 避免对共享资源的多重占用(比如写文件操作)。 - **缺点**:不适用于变化频繁的对象;实例化的对象长时间不被利用,可能被回收。 - **应用场景**: - 需要频繁实例化然后销毁的对象; - 需要对共享资源(数据库、文件)进行频繁读写的对象; - 创建对象时耗时或者耗资源过多,但又经常用到的对象。 - **实现**: - **函数装饰器**: ```python def singleton(cls): _instance = {} def inner(): if cls not in _instance: _instance[cls] = cls() return _instance[cls] return inner @singleton class Cls(object): def __init__(self): pass cls1 = Cls() cls2 = Cls() print(id(cls1) == id(cls2)) ``` - **类装饰器**: ```python class Singleton(object): def __init__(self, cls): self._cls = cls self._instance = {} def __call__(self): if self._cls not in self._instance: self._instance[self._cls] = self._cls() return self._instance[self._cls] @Singleton class Cls2(object): def __init__(self): pass cls1 = Cls2() cls2 = Cls2() print(id(cls1) == id(cls2)) ``` - **new关键字**: ```python class Single(object): _instance = None def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = object.__new__(cls, *args, **kw) return cls._instance def __init__(self): pass single1 = Single() single2 = Single() print(id(single1) == id(single2)) ```