python高级特性

  • 生成器

    • 常用于遍历元素
    • 如果使用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  # 会先用最近的装饰器进行装饰,最后输出 $<>$
    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
    
    • 匹配分组
      • 语法python高级特性_第1张图片
      • 举例1:指定分组序号
      # 识别
      # pat = r"<(.+)><(.+).+"  # 这样不能保证匹配到对应的/title(如/abc也匹配)
      pat = r"<(.+)><(.+).+"  # 使用指定组的匹配能保证得到对应的/title
      s = "我是标题"
      v = re.match(pat, s)
      print(v)
      
      • 举例2:指定分组名称以及引用别名
      s = "我是标题"
      pat = r"<(?P.+)><(?P.+).+"
      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()
      

python高级特性_第2张图片

你可能感兴趣的:(技术问题,#,python,python,内存管理)