一、装饰器
In [1]: def fn():
...: '''this is fn'''
...:
In [2]: help(fn)
Help on function fn in module __main__:
fn()
this is fn
In [4]: fn.__doc__ # 存储函数的文档
Out[4]: 'this is fn'
In [5]: fn.__name__ # 存储函数的名字
Out[5]: 'fn'
In [6]: dir(fn) # 查看fn 所有的 内嵌方法
Out[6]:
['__annotations__',
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__get__',
'__getattribute__',
'__globals__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__kwdefaults__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__']
In [7]:
In [2]: def logger(fn):
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: print('{} called took {}'.format(fn.__name__, end - star
...: t))
...: return ret
...: copy_propertities(fn, wrap)
...: return wrap
...:
In [3]: def copy_propertities(src, dst):
...: dst.__name__ = src.__name__
...: dst.__doc__ = src.__doc__
...:
In [4]: @logger
...: def sleep(x):
...: '''this is sleep'''
...: time.sleep(x)
...:
In [5]: import time, datetime
In [6]: sleep.__doc__
Out[6]: 'this is sleep'
In [7]: sleep.__name__
Out[7]: 'sleep'
In [8]:
In [8]: def copy_propertities(src): # 柯里化
...: def _copy(dst):
...: dst.__name__ = src.__name__
...: dst.__doc__ = src.__doc__
...: return _copy
...:
In [9]: def logger(fn):
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: print('{} called took {}'.format(fn.__nam
...: e__, end - start))
...: return ret
...: copy_propertities(fn)(wrap)
...: return wrap
...:
In [10]: @logger
...: def sleep(x):
...: '''this is sleep'''
...: time.sleep(x)
...:
In [11]: sleep.__doc__
Out[11]: 'this is sleep'
In [12]: sleep.__name__
Out[12]: 'sleep'
In [13]: def copy_propertities(src): # 柯里化,带参数的装饰器
...: def _copy(dst):
...: dst.__name__ = src.__name__
...: dst.__doc__ = src.__doc__
...: return dst
...: return _copy
...:
In [14]:
In [14]: def logger(fn):
...: @copy_propertities(fn)
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: print('{} called took {}'.format(fn.__na
...: me__, end - start))
...: return ret
...: return wrap
...:
In [15]: @logger
...: def sleep(x):
...: '''this is sleep'''
...: time.sleep(x)
...:
In [16]: sleep.__doc__
Out[16]: 'this is sleep'
In [17]: sleep.__name__
Out[17]: 'sleep'
In [18]:
-
AOP: 面向切面编程, 为了解决一类问题
In [19]: import functools
In [20]: help(functools.wraps)
Help on function wraps in module functools:
wraps(wrapped, assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'), updated=('__dict__',))
Decorator factory to apply update_wrapper() to a wrapper function
Returns a decorator that invokes update_wrapper() with the decorated
function as the wrapper argument and the arguments to wraps() as the
remaining arguments. Default arguments are as for update_wrapper().
This is a convenience function to simplify applying partial() to
update_wrapper().
(END)
In [21]: def logger(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: print('{} called took {}'.format(fn.__na
...: me__, end - start))
...: return ret
...: return wrap
...:
In [22]: @logger(2)
...: def sleep(x):
...: '''this is sleep'''
...: time.sleep(x)
...:
---------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-26fda312a82d> in <module>()
----> 1 @logger(2)
2 def sleep(x):
3 '''this is sleep'''
4 time.sleep(x)
5
<ipython-input-21-5b4e194e9175> in wrap(*args, **kwargs)
3 def wrap(*args, **kwargs):
4 start = datetime.datetime.now()
----> 5 ret = fn(*args, **kwargs)
6 end = datetime.datetime.now()
7 print('{} called took {}'.format(fn.__name__, end - start))
TypeError: 'int' object is not callable
In [23]: sleep.__name__
Out[23]: 'sleep'
In [24]: sleep.__doc__
Out[24]: 'this is sleep'
In [25]: start = datetime.datetime.now()
In [26]: end = datetime.datetime.now()
In [27]: delta = end - start
In [28]: delta.seconds
Out[28]: 9
In [29]:
In [29]: def logger(s):
...: def _logger(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: if (end - start).seconds > s:
...: print('{} called took {}'.format
...: (fn.__name__, end - start))
...: return ret
...: return wrap
...: return _logger
...:
In [30]: @logger(2)
...: def sleep(x):
...: time.sleep(x)
...:
In [31]: sleep(3)
sleep called took 0:00:03.003120
In [32]: sleep(1)
In [33]: logger(2)(sleep)(3)
sleep called took 0:00:03.003038
sleep called took 0:00:03.003127
In [34]:
In [34]: def logger(s, p=lambda name, t: print('call {} t
...: ook {}'.format(name, t))):
...: def _logger(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: if (end - start).seconds > s:
...: p(fn.__name__, end - start)
...: return ret
...: return wrap
...: return _logger
...:
In [35]: @logger(2)
...: def sleep(x):
...: time.sleep(x)
...:
In [36]: sleep(1)
In [37]: sleep(3)
call sleep took 0:00:03.003093
In [38]:
所以,装饰器的作用就是 在不改变函数本身的情况下,做一些预定义的逻辑处理
In [38]: @logger(2, p=lambda name, t: None)
...: def sleep(x):
...: time.sleep(x)
...:
In [39]: sleep(1)
In [40]: sleep(3)
In [41]: def logger(s):
...: def _logger(p=lambda name, t: print('call {}
...: took {}'.format(name, t))):
...: def __logger(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: start = datetime.datetime.now()
...: ret = fn(*args, **kwargs)
...: end = datetime.datetime.now()
...: if (end - start).seconds > s:
...: p(fn.__name__, end - start)
...: return ret
...: return wrap
...: return __logger
...: return _logger
...:
In [42]: @logger(2)()
...: def sleep(x):
...: time.sleep(x)
File "<ipython-input-42-c5a11f3c0ec8>", line 1
@logger(2)()
^
SyntaxError: invalid syntax
In [43]: logger(2)()(sleep)(3)
call sleep took 0:00:03.003091
In [44]: lg = logger(2)
In [45]: lg
Out[45]: <function __main__.logger.<locals>._logger>
In [46]: @lg()
...: def sleep(x):
...: time.sleep(x)
...:
In [47]: sleep(3)
call sleep took 0:00:03.002025
In [48]:
二、类型注解
In [1]: a = 1
In [2]: type(a)
Out[2]: int
In [3]: a = 's'
In [4]: def add(x, y):
...: return x + y
...:
In [5]: add(1, 3)
Out[5]: 4
In [6]: add('a', 'b')
Out[6]: 'ab'
In [7]: add(1, 'a')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-001bda6fec17> in <module>()
----> 1 add(1, 'a')
<ipython-input-4-5f28f1822fab> in add(x, y)
1 def add(x, y):
----> 2 return x + y
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [8]: def fn():
...: '''
...: 总是返回True
...: return True
...: '''
...: return False
...:
In [9]: def add(x: int, y: int) -> int:
...: return x + y
...:
In [10]:
- 冒号后面跟 参数类型
- 箭头后面跟 返回值类型
In [10]: add.__annotations__
Out[10]: {'return': int, 'x': int, 'y': int}
In [11]: import typing
In [12]: def _sum(lst: typing.List[int]) -> int:
...: ret = 0
...: for x in lst:
...: ret += x
...: return ret
...:
In [13]: _sum.__annotations__
Out[13]: {'lst': typing.List[int], 'return': int}
In [14]: import inspect
In [16]: sig = inspect.signature(add)
In [17]: list(sig.parameters.values())[0].annotation
Out[17]: int
In [18]: sig.parameters['x'].annotation
Out[18]: int
In [19]: sig
Out[19]: <Signature (x:int, y:int) -> int>
In [20]: sig.parameters['x']
Out[20]: <Parameter "x:int">
In [21]: sig.parameters['x'].annotation
Out[21]: int
In [22]: sig.parameters.values()
Out[22]: odict_values([<Parameter "x:int">, <Parameter "y:int">])
In [23]: sig.parameters['x'].name
Out[23]: 'x'
In [28]: @type # 框架
...: def add(x: int, y: int) -> int:
...: return x + y
...: add(1, 'a') # raise,print
...:
In [8]: import functools, inspect
In [9]: def typed(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: params = inspect.signature(fn).parameters
...:
...: # kwargs 检查
...: for k, v in kwargs.items():
...: if not isinstance(v, params[k].annotation):
...: raise TypeError('parameter {} require {}, but {}'.format(k, params[k].annot
...: ation, type(k)))
...:
...:
...: # args 检查
...: for i, arg in enumerate(args):
...: param = list(params.values())[i]
...: if not isinstance(arg, param.annotation):
...: raise TypeError('paramter {} require {}, but {}'.format(param.name, param.a
...: nnotation, type(arg)))
...: return fn(*args, **kwargs)
...: return wrap
...:
In [10]: @typed
...: def add(x: int, y: int) -> int:
...: return x + y
...:
In [11]: add(3, 2)
Out[11]: 5
In [12]: add(3, 'a')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-39bc36d291f5> in <module>()
----> 1 add(3, 'a')
<ipython-input-9-6908a9ee8192> in wrap(*args, **kwargs)
14 param = list(params.values())[i]
15 if not isinstance(arg, param.annotation):
---> 16 raise TypeError('paramter {} require {}, but {}'.format(param.name, param.annotation, type(arg)))
17 return fn(*args, **kwargs)
18 return wrap
TypeError: paramter y require <class 'int'>, but <class 'str'>
In [13]: add(y=3, x='a')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-6d2bbb3e8895> in <module>()
----> 1 add(y=3, x='a')
<ipython-input-9-6908a9ee8192> in wrap(*args, **kwargs)
7 for k, v in kwargs.items():
8 if not isinstance(v, params[k].annotation):
----> 9 raise TypeError('parameter {} require {}, but {}'.format(k, params[k].annotation, type(k)))
10
11
TypeError: parameter x require <class 'int'>, but <class 'str'>
In [14]:
In [15]: @typed
...: def add(x: int, y) -> int:
...: return x + y
...:
In [16]: add(1, 1) # 上面的代码,漏掉了如果参数的类型没有提供的情况。下面进行改进
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-d6a28b0c7f0b> in <module>()
----> 1 add(1, 1)
<ipython-input-9-6908a9ee8192> in wrap(*args, **kwargs)
14 param = list(params.values())[i]
15 if not isinstance(arg, param.annotation):
---> 16 raise TypeError('paramter {} require {}, but {}'.format(param.name, param.annotation, type(arg)))
17 return fn(*args, **kwargs)
18 return wrap
TypeError: paramter y require <class 'inspect._empty'>, but <class 'int'>
In [17]:
# 上面的代码,漏掉了如果参数的类型没有提供的情况。下面进行改进
# 类型检查(改进后)
In [23]: import functools, inspect
In [24]: def typed(fn):
...: @functools.wraps(fn)
...: def wrap(*args, **kwargs):
...: params = inspect.signature(fn).parameters
...:
...:
...: # kwargs 检查
...: for k, v in kwargs.items():
...: param = params[k]
...: if param.annotation != inspect._empty and not isinstance(v, param.annotation):
...:
...: raise TypeError('parameter {} require {}, but {}'.format(k, params[k].anno
...: tation, type(k)))
...:
...: # args 检查
...: for i, arg in enumerate(args):
...: param = list(params.values())[i]
...: if param.annotation != inspect._empty and not isinstance(arg, param.annotation
...: ):
...: raise TypeError('parameter {} require {}, but {}'.format(param.name, param
...: .annotation, type(arg)))
...: return fn(*args, **kwargs)
...: return wrap
...:
In [25]: @typed
...: def add(x: int, y: int) -> int:
...: return x + y
...:
In [26]: add(3, 5)
Out[26]: 8
In [27]: add(3, 'a')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-27-39bc36d291f5> in <module>()
----> 1 add(3, 'a')
<ipython-input-24-22f251518b19> in wrap(*args, **kwargs)
15 param = list(params.values())[i]
16 if param.annotation != inspect._empty and not isinstance(arg, param.annotation):
---> 17 raise TypeError('parameter {} require {}, but {}'.format(param.name, param.annotation, type(arg)))
18 return fn(*args, **kwargs)
19 return wrap
TypeError: parameter y require <class 'int'>, but <class 'str'>
In [28]: @typed
...: def add(x: int, y) -> int:
...: return x + y
...:
In [29]: add(3, 5)
Out[29]: 8
In [30]:
接受一个函数参数,然后把这个函数的某些参数变成默认参数,并返回一个新函数
来源:oschina
链接:https://my.oschina.net/u/3552459/blog/1569860