赞
踩
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2023/8/17 23:23
- # @Author : Maple
- # @File : 10-为类和静态方法提供装饰器.py
- import time
-
-
- def TimeCount(func):
-
- def wrapper(*args,**kwargs):
- start_time = time.perf_counter()
- r = func(*args,**kwargs)
- print('time takes {}s'.format(time.perf_counter() - start_time))
- return r
-
- return wrapper
-
- class A:
-
- # 注意装饰器的顺序不能写错
- @staticmethod
- @TimeCount
- def add(a,b):
- return a + b
- @classmethod
- @TimeCount
- def show(cls,n):
- return n
-
- if __name__ == '__main__':
-
- # 测试
- a = A()
- result1 = a.add(1,3)
- print(result1)
- """
- time takes 2.0999577827751637e-06s
- 4
- """
-
- print('--------------------')
-
- result2 = A.show(10)
- print(result2)
- """
- time takes 7.00005330145359e-07s
- 10
- """
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2024-04-07 16:23
- # @Author : Maple
- # @File : 09-将装饰器定义为类.py
-
-
-
- import types
- from functools import wraps
-
-
- class Profiled:
- def __init__(self, func):
- wraps(func)(self)
- self.ncalls = 0
-
- def __call__(self, *args, **kwargs):
- self.ncalls += 1
- # 执行被包装的函数func
- return self.__wrapped__(*args, **kwargs)
-
- def __get__(self, instance, cls):
- if instance is None:
- # print(self)
- return self
- else:
- # self其实就指向被包装的函数-->return self.__wrapper__(args,kwargs)
- # 这也是为何要实现__call__,因为能够实现profiled()这种写法-->会执行__call__方法,而__call__方法
- ## 返回的是对fun的调用
- # 为实例instance绑定fun
- return types.MethodType(self, instance)
-
-
- @Profiled
- def add(x,y):
- return x + y
-
- class Spam:
-
- @Profiled
- def bar(self,x):
- print(self,x)
-
-
- if __name__ == '__main__':
- a = add
- print(a) # <__main__.Profiled object at 0x0000018200971E50>
-
- print(add.ncalls) # 0
- # 本质上调用Profiled类中的call方法,因此ncall会+1
- add(12,2)
-
- print(add.ncalls) # 1
-
- s = Spam()
- print('s-->', s) # s--> <__main__.Spam object at 0x0000024770602180>
- # 会进到Profiled中的__get__方法,然后为s绑定 bar方法(同时这个bar是被Profiled包装过的)
- # 因此当执行s.bar时,实际是执行profiled()--> 会执行Profiled中的call--> ncall会被+1
- """
- s.bar(2)的完整执行流程:
- 1. 跳转到Profiled中的__get__方法,为s绑定一个profield实例--name为bar(profiled实例中包装了bar函数)
- 2. 因此s.bar(2)会执行Profiled类中的call,将ncall + 1
- 3. 然后通过self.__wrapped__(*args, **kwargs) -->执行bar函数本身的逻辑: print(self,x)
- 4. 最后return self.__wrapped__(*args, **kwargs)的返回值:此例为null,无返回值
- """
-
- s.bar(2)
- print(s.bar.ncalls) # 1
- s.bar(3)
- print(s.bar.ncalls) # 2
-
- print('****************************')
-
- s = Spam.bar(0,1)
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2023/8/17 23:23
- # @Author : Maple
- # @File : 10-为类和静态方法提供装饰器.py
- import time
-
-
- def TimeCount(func):
-
- def wrapper(*args,**kwargs):
- start_time = time.perf_counter()
- r = func(*args,**kwargs)
- print('time takes {}s'.format(time.perf_counter() - start_time))
- return r
-
- return wrapper
-
- class A:
-
- # 注意装饰器的顺序不能写错
- @staticmethod
- @TimeCount
- def add(a,b):
- return a + b
- @classmethod
- @TimeCount
- def show(cls,n):
- return n
-
- if __name__ == '__main__':
-
- # 测试
- a = A()
- result1 = a.add(1,3)
- print(result1)
- """
- time takes 2.0999577827751637e-06s
- 4
- """
-
- print('--------------------')
-
- result2 = A.show(10)
- print(result2)
- """
- time takes 7.00005330145359e-07s
- 10
- """
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2024-04-07 16:23
- # @Author : Maple
- # @File : 11-装饰器为包装函数增加参数.py
-
-
-
- import inspect
- from functools import wraps
-
-
- def optional_debug(func):
-
- @wraps(func)
- def wrapper(*args,debug=False,**kwargs):
- if debug:
- print('calling ' + func.__name__)
- return func(*args,**kwargs)
- return wrapper
-
-
- @optional_debug
- def add(x,y):
- return x + y
-
-
- """
- 通过装饰器来给被包装函数增加参数的做法并不常见。
- 尽管如此,有时候它可以避免一些重复代码。例如,如果你有下面这样的代码:
- """
- def a(x, debug=False):
- if debug:
- print('Calling a')
-
- def b(x, y, z, debug=False):
- if debug:
- print('Calling b')
-
- def c(x, y, debug=False):
- if debug:
- print('Calling c')
-
-
- def optional_debug2(func):
- if 'debug' in inspect.getfullargspec(func).args:
- print('inspect.getfullargspec(func).args',inspect.getfullargspec(func).args) # ['x', 'y', 'debug']
- raise TypeError('debug argument already defined')
-
- @wraps(func)
- def wrapper(*args,debug=False,**kwargs):
- if debug:
- print('calling', func.__name__)
- return func(*args,**kwargs)
-
- return wrapper
-
-
-
- """如果函数本身已存在debug参数,会触发装饰器中的raise TypeError
- """
- # @optional_debug2
- # def add2(x,y,debug):
- # if debug:
- # print('calling add2')
- # return x + y
-
- @optional_debug2
- def add3(x,y):
- return x + y
-
-
-
- def optional_debug3(func):
- if 'debug' in inspect.getfullargspec(func).args:
- print('inspect.getfullargspec(func).args',inspect.getfullargspec(func).args) # ['x', 'y', 'debug']
- raise TypeError('debug argument already defined')
-
- @wraps(func)
- def wrapper(*args,debug=False,**kwargs):
- if debug:
- print('calling', func.__name__)
- return func(*args,**kwargs)
-
- sig = inspect.signature(func)
- # 获取func函数的参数列表
- param = list(sig.parameters.values())
-
- # 添加debug参数
- param.append(inspect.Parameter('debug',
- inspect.Parameter.KEYWORD_ONLY,
- default=False))
-
- wrapper.__signature__ = sig.replace(parameters=param)
- return wrapper
-
-
- @optional_debug3
- def add4(x,y):
- return x + y
-
-
-
- if __name__ == '__main__':
-
- # 1.optional_debug测试
- r = add(1,2,debug = True) # calling add
- print(r) # 3
-
- print('2-1.optional_debug2 -测试1')
- # 2-1.optional_debug2 -测试1
- # try:
- # add2(1,2)
- # except TypeError as e:
- # print(e) # debug argument already defined
-
- print(' 2-2.optional_debug2 -测试2')
- # 2-2.optional_debug2 -测试2
- r2 = add3(2,2,debug = True) # calling add3
- print(r2) # 4
-
- print('2-3.optional_debug2存在一个问题')
- # 2-3.optional_debug2存在一个问题
- # 被装饰的add3元数据中并没有debug参数(本意是想通过装饰器添加额外参数)
- print(inspect.signature(add3)) # (x, y)
-
- # 3. 修复被装饰函数debug参数丢失问题
- print(inspect.signature(add4)) # (x, y, *, debug=False)
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2024-04-07 17:24
- # @Author : Maple
- # @File : 12-使用类装饰器扩充类的功能.py
-
- """通过反省或者重写类定义的某部分来修改它的行为,但是你又不希望使用继承或元类的方式。
- """
-
- def log_getattribute(cls):
-
- org_getattribute = cls.__getattribute__
-
- def new_getattribute(self,name):
- print('getting ',name)
- return org_getattribute(self,name)
-
- cls.__getattribute__ = new_getattribute
-
- return cls
-
- @log_getattribute
- class A:
- def __init__(self,x):
- self.x = x
-
- def spam(self):
- pass
-
- if __name__ == '__main__':
-
- # 1.属性测试
- a = A('Maple') # getting x
- print(a.x) # Maple
-
- # 2.方法测试
- a.spam() #getting spam
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @Time : 2024-04-07 17:43
- # @Author : Maple
- # @File : 13-使用元类控制实例的创建.py
-
- """
- 元类是type类的子类
- """
-
- class NoInstance(type):
- def __call__(self, *args, **kwargs):
- raise TypeError("can't instanciate directly")
-
- class Person(metaclass=NoInstance):
-
- def __init__(self,name):
- self.name = name
-
- @staticmethod
- def run():
- print('grok is running')
-
-
- """利用元类实现单列模式
- """
-
- class Singleton(type):
-
- # init方法是完成类(此例中是 Student )的初始化
- # self表示Student类, cls.__instance即为类添加了一个类属性
- def __init__(cls,*args,**kwargs):
- # self代表元类Singleton的实例(注意元类是用来创建类的,因此其实例对象是一个类)
- # 因此,此例中self代表Student类
- cls.__instance = None
- # super()代表type
- """
- *args 和 **kwargs:这些是位置参数和关键字参数的列表,它们在创建类对象时被传递给 type 的构造函数。通常,这些参数包括:
-
- --下面这3个参数其实都位于args元组中--
- name:字符串,代表正在被创建的类的名称。
- bases:元组,包含了类的所有基类。
- class_dict:字典,包含了类定义中的所有属性和方法。
- """
- print('__init__方法中的args')
- for a in args:
- print('a: ',a)
-
- # 调用type的init方法,初始化需要创建的类:此例是Student
- super().__init__(*args,**kwargs)
-
-
- # 当要创建的类(此例中是 Student 类) 实例化时,会调用元类的call方法
- def __call__(cls, *args, **kwargs):
- #
- if cls.__instance is None:
- print('__call__方法中的args')
- """
- a: Maple
- a: 19
- """
- for a in args:
- print('a: ', a)
-
- # 调用type的call方法,返回一个实例对象(student),并存放在Student类的__instance属性中
- # cls是Student类
- cls.__instance = super().__call__(*args,**kwargs)
- return cls.__instance
- else:
- return cls.__instance
-
-
- class Student(metaclass=Singleton):
- def __init__(self,name,age):
- self.name = name
- self.age = age
-
-
-
- if __name__ == '__main__':
-
- # 1. Person不能被实例化,run方法只能通过类调用
- print('******** 1. Person不能被实例化,run方法只能通过类调用***************')
- Person.run() # grok is running
-
- try:
- p = Person('Maple')
- except TypeError as e:
- print(e) # can't instanciate directly
-
-
- print('********2. 单例测试****************')
- ## 2-1 类属性查看
- print(Student.__dict__) # {...Singleton__instance': None}
-
- ## 2-2 初始化实例对象
- s1 = Student('Maple',19)
- print(Student.__dict__) # {..._Singleton__instance': <__main__.Student object at 0x00000180EB622D80>}}
- s2 = Student('Maple', 19)
- print(Student.__dict__) # {..._Singleton__instance': <__main__.Student object at 0x00000180EB622D80>}}
- print(s1 is s2) # True
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。