1,装饰器:就是一个函数,可以接受一个函数作为输入并返回一个新的函数
from functools import wraps
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return 'Point2D: [{!s}, {!s}]'.format(self.x, self.y)
# 装饰器,对Point2D对象检测,如果小于0 就置为0
def Add_Checker(func):
@wraps(func)# 拷贝装饰器的元数据
def wrapper(a, b):
if a.x < 0 or a.y < 0:
a = Point2D(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
if b.x < 0 or b.y < 0:
b = Point2D(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
ret = func(a, b)
return ret
return wrapper
def no_add(a, b):
return Point2D(a.x + b.x, a.y + b.y)
@Add_Checker
def add(a, b):
print(a, b)
return Point2D(a.x + b.x, a.y + b.y)
a = Point2D(1,-2)
b = Point2D(-3, 4)
print(no_add(a, b))
print(add(a, b))
orig_add = add.__wrapped__ #对装饰器进行解包装
print(orig_add(a, b))
out:
Point2D: [-2, 2]
Point2D: [1, 0] Point2D: [0, 4]
Point2D: [1, 4]
Point2D: [1, -2] Point2D: [-3, 4]
Point2D: [-2, 2]
2, 实现外部调整装饰器的属性,使得在运行时能够控制装饰器行为
from functools import wraps, partial
def attach_wrapper(obj, func=None):
if func is None:
return partial(attach_wrapper, obj)
setattr(obj, func.__name__, func)
return func
def Student(id, name=None, addr=None):
def decorate(func):
stud_id = id
stud_name = name if name else 'XiaoMing'
stud_addr = addr if addr else 'xxx'
@wraps(func)
def wrapper(*args, **kwargs):
print(stud_id, ': ', stud_name, ':', stud_addr);
return func(*args, **kwargs)
#访问器函数用来修改装饰器的属性
@attach_wrapper(wrapper)
def set_name(newname):
nonlocal stud_name #通过对nonlocal变量赋值来调整内部参数
stud_name = newname
@attach_wrapper(wrapper)
def set_addr(newaddr):
nonlocal stud_addr
stud_addr = newaddr
return wrapper
return decorate
@Student(1)
def do_what(what):
print('do '+what)
do_what('homework')
do_what.set_name('Leon')
do_what('homework')
do_what.set_addr('PeopleSquare 15#')
do_what('homework')
out:
1 : XiaoMing : xxx
do homework
1 : Leon : xxx
do homework
1 : Leon : PeopleSquare 15#
do homework
3,利用装饰器对函数参数强制执行类型检查
from inspect import signature
from functools import wraps
def typeassert(*ty_args, **ty_kwargs):
def decorate(func):
# 全局变量__debug__被设为False时,返回未修改的函数
if not __debug__:
return func
# 从一个可调用对象中提取出参数签名信息
sig = signature(func)
# 对提供的类型到参数做部分绑定,创建了有序字典
bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
@wraps(func)
def wrapper(*args, **kwargs):
# 不允许出现缺失的参数
bound_value = sig.bind(*args, **kwargs)
for name, value in bound_value.arguments.items():
if name in bound_types:
if not isinstance(value, bound_types[name]):
raise TypeError(
'Argument {} must be {}'.format(name, bound_types[name])
)
return func(*args, **kwargs)
return wrapper
return decorate
@typeassert(int, int)
def add(x, y):
print(x+y)
add(1, 2)
add(1, 'sdf')
out:
3
Traceback (most recent call last)...
TypeError: Argument y must be <class 'int'>
4, 实现单例模式
#实现单例模式
class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super().__call__(*args, **kwargs)
return self.__instance
else:
return self.__instance
class Spam(metaclass = Singleton):
def __init__(self):
print('Creating Spam')
a = Spam()
b = Spam()
print (a == b)
out:
Creating Spam
True
#单例实现的另一种技巧
class _Spam:
def __init__(self):
print('Creating Spam')
_spam_instance = None
def Spam():
global _spam_instance
if _spam_instance is not None:
return _spam_instance
else:
_spam_instance = _Spam()
return _spam_instance
5,创建缓存实例
方法一:
import weakref
class Spam():
# 不能直接实例化该类
def __init__(self, *args, **kwargs):
raise RuntimeError('Cannot initialized directly')
# 用类的方法实现构造函数的功能
@classmethod
def _new(cls, name):
self = cls.__new__(cls)
self.name = name
return self
class CacheSpamMgr:
def __init__(self):
self._cache = weakref.WeakValueDictionary()
def get_spam(self, name):
if name not in self._cache:
s = Spam._new(name)
self._cache[name] = s
else:
s = self._cache[name]
return s
mgr = CacheSpamMgr()
a = mgr.get_spam('Leon')
b = mgr.get_spam('xxx')
c = mgr.get_spam('Leon')
print('a == b is', (a is b))
print('a == c is',(a is c))
out:
a == b is False
a == c is True
方法二:
import weakref
#利用元类实现创建缓存实例
class Cached(type):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__cache = weakref.WeakValueDictionary()
def __call__(self, *args):
if args in self.__cache:
return self.__cache[args]
else:
obj = super().__call__(*args)
self.__cache[args] = obj
return obj
class Spam(metaclass=Cached):
def __init__(self, name):
print('Creating Spam ({!r})'.format(name))
self.name = name
a = Spam('Leon')
b = Spam('x')
c = Spam('Leon')
print('a == b is', (a is b))
print('a == c is',(a is c))
out:
Creating Spam ('Leon')
Creating Spam ('x')
a == b is False
a == c is True