【问题标题】:Python: decorator specific argument (unrelated to wrapped function)?Python:装饰器特定参数(与包装函数无关)?
【发布时间】:2010-10-14 05:28:36
【问题描述】:

我正在寻找构建一个缓存装饰器,它给定一个函数将函数的结果缓存到装饰中指定的位置。像这样的:

@cacheable('/path/to/cache/file')
def my_function(a, b, c):
    return 'something'

装饰器的参数与它包装的函数的参数完全分开。我已经查看了很多示例,但我不太了解如何执行此操作 - 是否可以为装饰器提供一个与包装函数无关且未传递给包装函数的参数?

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    Paul 的回答很好,我会移动缓存对象,这样就不需要每次都构建它,并设计你的缓存,以便在缓存未命中时引发 KeyError:

    def 缓存(文件路径):
        def 装饰器(f):
            f._cache = 缓存(缓存路径)
            def 装饰(*args,**kwargs):
                尝试:
                    键 = (args, kwargs)
                    res = f._cache.get(key)
                除了 KeyError:
                    res = f(*args, **kwargs)
                    f._cache.put(key, res)
                返回资源
            返回装饰
        返回装饰器
    

    【讨论】:

      【解决方案2】:

      这个想法是你的装饰器是一个返回装饰器的函数。

      FIRST 编写您的装饰器,就好像您知道您的参数是一个全局变量一样。让我们这样说:

      -

      def decorator(f):
        def decorated(*args,**kwargs):
            cache = Cache(cachepath)
            if cache.iscached(*args,**kwargs):
                ...
            else:
                res = f(*args,**kwargs)
                cache.store((*args,**kwargs), res)
                return res
        return decorated
      

      那么编写一个函数,将 cachepath 作为 arg 并返回您的装饰器。

      -

      def cache(filepath)
          def decorator(f):
            def decorated(*args,**kwargs):
                cache = Cache(cachepath)
                if cache.iscached(*args,**kwargs):
                    ...
                else:
                    res = f(*args,**kwargs)
                    cache.store((*args,**kwargs), res)
                    return res
            return decorated
          return decorator
      

      【讨论】:

        【解决方案3】:

        是的。如您所知,装饰器是一个函数。当写在表格中时:

        def mydecorator(func):
           def wrapper(*args, **kwargs):
               return func(*args, **kwargs)
           return wrapper
        
        @mydecorator
        def foo(a, b, c):
            pass
        

        传递给mydecorator 的参数是函数foo 本身。

        当装饰器接受一个参数时,调用@mydecorator('/path/to')实际上会首先调用带有'/path/to'的mydecorator函数。然后调用mydecorator(path)的结果会被调用来接收函数foo。您实际上是在定义一个动态包装函数。

        简而言之,你需要另一层装饰器函数。

        这是一个有点傻的例子:

        def addint(val):
            def decorator(func):
                def wrapped(*args, **kwargs):
                    result = func(*args, **kwargs)
                    return result + val
                return wrapped # returns the decorated function "add_together"
             return decorator # returns the definition of the decorator "addint"
                              # specifically built to return an extra 5 to the sum
        
        @addint(5)
        def add_together(a, b):
            return a + b
        
        print add_together(1, 2)
        # prints 8, not 3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-15
          • 2011-06-25
          • 2015-09-03
          • 2014-07-21
          • 1970-01-01
          • 2016-09-27
          • 1970-01-01
          • 2023-03-31
          相关资源
          最近更新 更多