PythonCookBook 筆記 chapter-09-超程式設計
阿新 • • 發佈:2018-12-19
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