-
生成器
- 常用于遍历元素
- 如果使用list,通常耗时多且内存消耗也多,举例如下
import time, sys time.clock() list1 = [x for x in range(2, 100000000, 2)] cost_time = time.cloce() print("创建list1耗时 %g" % cost_time) # %g 表示科学计数法 print("创建list1内存开销 %d" % sys.getsizeof(list1)) # 获取字节数 # =========================生成器 g1 = (x for x in range(2, 100000000, 2)) # g1类型是generator print(next(g1))
-
闭包和装饰器/注解
- 举个例子
def funcOut(num1): def funcIn(num2): return num2 + num1 return funcIn fin = funcOut(1) res = fin(2) res1 = fin(3) # ========如果希望在funcIn内修改num1========== def funcOut(num1): def funcIn(num2): nonlocal num1 # 需要声明非局部变量,类似global num1 += 1 return num2 + num1 return funcIn fin = funcOut(1)
- 闭包的好处是,外部函数funcOut的变量num1,如果不常变动,就传递给内部函数funcIn,由内部函数处理变动的变量;比如要持续计算 一些点 离 原点的距离
- 闭包的特殊用处:可以在不修改现有源码的前提下,增加新的功能;如日志功能,权限验证
# 在已有功能的基础上添加日志,记录访问时间和功能名称,并写入日志文件 def write_log(func): try: file = open("log.txt", "a", encoding="utf8") file.write(func.__name__ + "\t") file.write(time.asctime() + "\n") except Exception as e: print(e.args) finally: file.close() def func1(): print("已完成功能1") # 直接修改已完成功能func1源代码,对func1添加日志记录 def func1(): write_log(func1) # 再已完成功能内部添加日志,可能造成功能可读性越来越差 print("已完成功能1") # 使用闭包,可以不直接修改已完成功能的源码代码 def funcOut(func): # 前面说过闭包一般funcOut的变量是不动,但也不是固定不变 def funcIn(): write_log(func) func() return funcIn func1 = funcOut(func1) # func1替代了对原有的func1的调用,接口完全一致;有人可能会觉得直接用funcOut而不用funcIn,但是这样可能会改变已有业务对func1调用的接口; # ============================= # 使用上述方法的缺点显而易见,func1 = funcOut(func1) 该行可能要写很多次;为了避免这种情况,我们使用注解 @funcOut # 注解or装饰器等价于 func1 = funcOut(func1) def func1(): print("已完成功能1") # 多装饰器 def funcOut1(func): def funcIn(): return "<<" + func() + ">>" return funcIn def funcOut2(func): def funcIn(): return "$" + func() + "$" return funcIn @funcOut2 @funcOut1 # 会先用最近的装饰器进行装饰,最后输出 $<<deeplearning>>$ def bookName(): return "deepLearning" # ============================== # 带多个参数的闭包和装饰器 def funcOut(func): def funcIn(x,y): # 从该例子可以看出,闭包通常只是新增功能,不更改原有功能的接口 # 此处新增功能 func(x,y) return funcIn @funcOut def test(a, b): print("a = %g b = %g"%(a,b)) test(1, 2) # ============================== # 通用装饰器 def funcOut(func): def funcIn(*args, **kwargs): # 利用*args 和 **kwargs print("新增功能") # 通用装饰器要求 新增功能 是共用 return func(*args, **kwargs) # 使用return,防止因func有返回值而报错 return funcIn @funcOut def func1(a): print("a = %g" % a) @funcOut def func2(a, b): print(f"a = {a} b = {b}") func1(10) func2(20, 30)
-
python动态语言
- 动态添加属性
class Person: def __init__(self, name, age): self.name = name self.age = age p1 = Person("aa", 10) p2 = Person("bb", 20) p1.gender = "女" # 对象p1动态添加gender属性 setattr(p1, "gender", "女") # 另一种添加方法 print(p2.gender) # 报错,p2没有添加gender属性 # 如果要统一对所有对象添加,这时候使用添加 类属性 Person.CLASS_ID = "01" print(p1.CLASS_ID) # 输出 01 print(p1.CLASS_ID) # 输出 01
- 动态添加方法(对象方法、静态方法、类方法)
# 给对象添加方法 import types def study(self): print("给对象添加了study方法") p1 = Person("aa", 10) p1.study = types.MethodType(study, p1) p1.study() # 添加静态方法 @staticmethod def testStaticMethod(): print("我是静态方法") Person.static_method = testStaticMethod # 给类添加静态方法 Person.static_method() # 添加类方法 @classmethod def testClsMethod(cls): print("我是类方法") Person.cls_method = testClsMethod p1.cls_method() Person.cls_method()
- __slots__的作用
- 限制添加对象属性,不限制添加类属性
class Person(): __slots__ = ("name", "age") def __init__(self, name, age): self.name = name slef.age = age p1 = Person("aa", 10) p1.gender = "女" # error __slots__指定了Person的属性,不允许对象自己添加属性、方法 Person.cls_id = 100 # 正确,此外不影响类添加 静态方法和类方法
- partial偏函数
- 固定某函数的部分参数,得到新的子函数;好处,可以省略某些参数的书写
from functools import partial str1 = "1010" resutl = int(str1, base=2) # int函数将str1转换成10机制,参数2指的是str1是二进制表示 int2 = partial(int, base=2) # 利用偏函数固定base print(int2(str1)) # 10
- wraps
- 常用于闭包;将原函数的某些属性传递给包装函数,如__name__,__doc__等
def log(func): @wraps(func) # 如果希望with_logging保留原函数test的信息,则加上该注解 def with_logging(*args, **kwargs): print(f"{func.__name__} called") return func(*args, **kwargs) return with_logging @log # 此时 test = log(test),即test=with_logging def test(x): """求x^2的值""" return x*x print(test.__name__) # with_logging -> 加上wraps注解后得到 test print(test.__doc__) # None -> 加上wraps注解后得到 求x^2的值
- filter
-filter(func, iterable) 利用func过滤iterable的元素,返回符合要求的元素
-
正则表达式
- 开头:^;结尾:$;单词边界:\b;非单词边界:\B
import re s = "123,eroa" pat = r".*\ber" # 注意\b本身是转义字符,需要加r先变成原生字符串,再由re去转义;该pat识别.*及er作为左边界的单词 print(re.match(pat, s)) # ret123,er
- 匹配分组
- 语法
- 举例1:指定分组序号
# 识别<html><title></title></html> # pat = r"<(.+)><(.+).+</.+></.+>" # 这样不能保证匹配到对应的/title(如/abc也匹配) pat = r"<(.+)><(.+).+</\2></\1>" # 使用指定组的匹配能保证得到对应的/title s = "<html><title>我是标题</title></html>" v = re.match(pat, s) print(v)
- 举例2:指定分组名称以及引用别名
s = "<html><title>我是标题</title></html>" pat = r"<(?P<k1>.+)><(?P<k2>.+).+</(?P=k2)></(?P=k1)>" v = re.match(pat, s) print(v)
- 语法
- 高级用法
- re.findall(pat, s)
- re.sub(pat, s)
def replace(result): # 利用函数处理返回的结果,并用新的结果替换 return str(int(result.group(0)) + 100000) s = "python阅读1000次,c阅读800次" pat = "/d+" v = re.sub(pat, replace, s)
- re.split()
s = "He says: Hello, World" pat = r"\s|:|," # 遇到\s : ,都进行切割 v = re.split(pat, s) # [He, says, Hello, World]
-
内存管理
- 元类
# type动态创建类 class Animal: def __init__(self, color): self.color = color def eat(self): pritn("动物需要吃食物") def sleep(): print("狗喜欢吃红薯") Dog = type("Dog", (Animal,), {"age": 3, "sleep": sleep}) dog = Dog("白色") print(dog.age) dog.sleep() dog.eat()
- 装饰器
- 使用类进行装饰,类似闭包的使用;
class DecClass: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): self.addFunc(*args, **kwargs) return self.func(*args, **kwargs) def addFunc(self): print("增加新功能,如日志,权限验证") @DecClass # test = DecClass(test) => 返回类对象,test()变成类对象的call def test(a, b, c): print("已完成功能,希望增加新功能")
- 大小整数池及intern机制
- 小整数池:[-5, 256],该范围的数值只有一份,且不会被回收
- 大整数池:不在上述范围内的整数
- 不含空格或者其他特殊符号的str,就是intern,str1=“hello” is str2=“hello”
- 垃圾回收机制
- python使用引用计数机制为主,标记-清除、分代收集 为辅
- 引用计数
- 增加:函数参数,添加到list
import sys class AA(): def __new__(cls, *args, **kwargs): print("开辟内存空间") return super(AA, cls).__new__(cls) def __init__(self): print("创建对象at: %s" % hex(id(self))) def __del__(self): print("%s say bye bye" % hex(id(self))) aa = AA() print("aa的引用计数为: %d" % sys.getrefcount(a)) # 初始化引用计数为2
- 隔代回收 (图片来自尚学堂)
- 可解决引用计数无法处理的 互相引用 的问题;
- 具体做法:3代,阈值;每一代对象数量达到阈值,gc会处理一次,然后把有用的对象保留给下一代,如此循环;
import gc, time class AA(): def __new__(cls, *args, **kwargs): print("内存开辟一个空间给新对象使用") return super(AA, cls).__newj__(cls) def __init__(self): print(f"对象{hex(id(self))}做一些初始化") def __del__(self): print(f"对象{hex(id(self))}被系统回收") def test(): while True: a = AA() b = AA() a.v = b # b的引用增加1次 b.v = a del a # 如果能删除a,则b的引用减少1次 del b print(gc.get_threshold()) # 700 10 10 print(gc.get_count()) # 事实发现无法删除,只能等达到阈值,进行被动回收 time.sleep(0.1) test()
- 元类