zoukankan      html  css  js  c++  java
  • 如何定义带参数装饰器?

    需求:
    实现一个装饰器,它用来检查被装饰函数的参数类型,装饰器可以通过参数来指明函数参数类型,调用时如果检测出参数不匹配则抛出异常

    @type_assert(str,int,int)
    def f(a,b,c):
    ....

    @type_assert(y=list)
    def g(x,y):
    ....

    思路:
    1、提取函数签名,inspect.signature()
    2、带参数的装饰器,也就是根据参数定制一个装饰器,可以看成是生产装饰器的工厂。每次调用type_assert,返回一个特定的装饰器,然后用它去修饰其他函数

    代码:

    import inspect
    
    # 带参数的装饰器,制造工厂的工厂
    def type_assert(*ty_args,**ty_kwargs):
        def decorator(func):
            # A...
            func_sig = inspect.signature(func)
            bind_type = func_sig.bind_partial(*ty_args,**ty_kwargs).arguments
            def wrap(*args,**kwargs):
                # B...
                for name,obj in func_sig.bind(*args,**kwargs).arguments.items():
                    type_ = bind_type.get(name)
                    if type_:
                        if not isinstance(obj,type_):
                            raise TypeError('%s must be %s' % (name,type_))
                return func(*args,**kwargs)
            return wrap
        return decorator
    
    @type_assert(c=str)
    def f(a,b,c):
        pass
    
    >>> def f(a,b,c):
    ...     pass
    ... 
    ... f_sig = inspect.signature(f)
    >>> f_sig.parameters
    mappingproxy(OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b">), ('c', <Parameter "c">)]))
    >>> pa = f_sig.parameters['a']
    >>> pa.name
    'a'
    >>> pa.kind
    <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>
    >>> pa.default
    <class 'inspect._empty'>
    >>> ba = f_sig.bind(int,int,str)
    >>> ba.arguments
    OrderedDict([('a', <class 'int'>), ('b', <class 'int'>), ('c', <class 'str'>)])
    >>> ba.arguments['a']
    <class 'int'>
    >>> f_sig.bind(str,list)
    Traceback (most recent call last):
      File "<ipython-input-35-8b202b51ffc9>", line 1, in <module>
        f_sig.bind(str,list)
      File "/home/richardo/anaconda3/lib/python3.7/inspect.py", line 3002, in bind
        return args[0]._bind(args[1:], kwargs)
      File "/home/richardo/anaconda3/lib/python3.7/inspect.py", line 2917, in _bind
        raise TypeError(msg) from None
    TypeError: missing a required argument: 'c'
    
    >>> f_sig.bind_partial(str,list)
    <BoundArguments (a=<class 'str'>, b=<class 'list'>)>
    >>> 
    

    f(5,10,[])

  • 相关阅读:
    [BZOJ1934][Shoi2007]Vote 善意的投票[最小割]
    [BZOJ1066][SCOI2007]蜥蜴[最大流]
    [BZOJ2818][P2568]Gcd[欧拉函数]
    [BZOJ2208][P4306][JSOI2010]连通数[bitset优化floyd]
    [BZOJ1877][SDOI2009]晨跑[最大流+费用流]
    [BZOJ1040][P2607][ZJOI2008]骑士[树形DP+基环树]
    [BZOJ5347]冒泡排序[思维]
    [BZOJ2875][Noi2012]随机数生成器[等比数列求和+取模]
    [bzoj2809] 派遣
    [bzoj1965] 洗牌
  • 原文地址:https://www.cnblogs.com/Richardo-M-Q/p/13958778.html
Copyright © 2011-2022 走看看