带有位置参数的函数的装饰器,带有通用命名参数

vol*_*ano 4 python decorator keyword-argument python-2.7

我有一组函数/方法,它们都有不同的位置参数集,在某些情况下还有关键字参数,但共享一个名为Lane_type 的字符串参数。它可以是位置参数或关键字参数。由于设计缺陷(有罪),不同地方的相同值在字符串中可能有大写字母。因此,为了进行比较,我必须将其转换为小写。最终我决定尝试通过装饰器进行转换:

def lt_dec(func):
    def _lt_lower(**kwargs):
        kwargs['lane_type'] = kwargs['lane_type'].lower()
        return func(**kwargs)
    return _lt_lower
Run Code Online (Sandbox Code Playgroud)

当然,我试图测试它 - 它失败了:

In [38]: @lt_dec
def test1(lane_type):
    print lane_type
   ....:     

In [39]: test1('Solid')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/homes/markg/<ipython-input-39-bb6cef5c7fad> in <module>()
----> 1 test1('Solid')

TypeError: _lt_lower() takes exactly 0 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

显然,我并不完全了解 **kwargs 替换机制。我将非常感谢我所缺少的解释以及我的问题是否有优雅的解决方案。

编辑:

我相信为了清楚起见,我应该展示一些函数定义的例子:这是一个类中的方法

def add_polygon(self, points, lane_type, color):
Run Code Online (Sandbox Code Playgroud)

另一个类的方法:

def __init__(self, points, lane_type, color, side=None):
Run Code Online (Sandbox Code Playgroud)

一个函数

def lane_weight(lane_type):
Run Code Online (Sandbox Code Playgroud)

当然,对于具有 1 个参数的函数(我有几个),解决方案很简单

def lt_dec(func):
    def _lt_lower(lane_type):
        return func(lane_type)
    return _lt_lower
Run Code Online (Sandbox Code Playgroud)

如上所述 - 是否有适用于所有示例的通用解决方案?(我准备接受否作为答案)

fal*_*tru 5

**kwargs在函数定义中使用,您将获得关键字参数(不是位置参数)作为字典:

>>> def lt_dec(func):
...     def _lt_lower(**kwargs):
...         print 'type(kwargs)=', type(kwargs)
...         print 'kwargs=', kwargs
...         kwargs['lane_type'] = kwargs['lane_type'].lower()
...         return func(**kwargs)
...     return _lt_lower
...
>>> @lt_dec
... def test1(lane_type):
...     print lane_type
...
>>> test1(lane_type='Solid')
type(kwargs)= <type 'dict'>
kwargs= {'lane_type': 'Solid'}
solid
Run Code Online (Sandbox Code Playgroud)
>>> def lt_dec(func):
...     def _lt_lower(*args, **kwargs):
...         if args:
...             args = (args[0].lower(),) + args[1:]
...         elif 'lane_type' in kwargs:
...             kwargs['lane_type'] = kwargs['lane_type'].lower()
...         return func(*args, **kwargs)
...     return _lt_lower
...
>>> @lt_dec
... def test1(lane_type):
...     print lane_type
...
>>> test1('Solid')
solid
>>> test1(lane_type='Solid')
solid
Run Code Online (Sandbox Code Playgroud)

更新

使用inspect.getcallargs

>>> import inspect
>>>
>>> def lt_dec(func):
...     def _lt_lower(*args, **kwargs):
...         kwargs = inspect.getcallargs(func, *args, **kwargs)
...         if 'lane_type' in kwargs:
...             kwargs['lane_type'] = kwargs['lane_type'].lower()
...         return func(**kwargs)
...     return _lt_lower
...
>>> @lt_dec
... def test1(blah, lane_type):
...     print lane_type
...
>>> test1('foo', 'Solid')
solid
>>> test1('foo', lane_type='Solid')
solid
Run Code Online (Sandbox Code Playgroud)