如果条件为True,则装饰一个函数?

时间:2013-12-31 01:57:56

标签: python python-2.7

我想做类似于此的事情,这可以理解为导致SyntaxError:

@api_view(['GET'])
if settings.USE_API_KEY:
    @authentication_classes((TokenAuthentication, ))
    @permission_classes((IsAuthenticated, ))
def all_announcements(request):
    announcements = Announcement.objects.all()
    serializer = AnnouncementSerializer(announcements, many=True)
    return Response(serializer.data)

我如何实现类似的东西?

5 个答案:

答案 0 :(得分:9)

我不会为此编写装饰器 - 请注意,装饰器语法允许返回装饰器的函数调用(实际上,这是decorators-with-parameters实际上做的)。所以:

def maybe_decorate(condition, decorator):
    return decorator if condition else lambda x: x

@api_view(['GET'])
@maybe_decorate(settings.USE_API_KEY, authentication_classes((TokenAuthentication, )))
@maybe_decorate(settings.USE_API_KEY, permission_classes((IsAuthenticated, )))
def all_announcements(request):
    ...

答案 1 :(得分:6)

当您使用这样的装饰器时:

@decorator
def f():
    ...

它等同于:

def f():
    ...
f = decorator(f)

考虑到这一点,你可以像这样完成你想要的东西:

def all_announcements(request):
    announcements = Announcement.objects.all()
    serializer = AnnouncementSerializer(announcements, many=True)
    return Response(serializer.data)

if settings.USE_API_KEY:
    all_announcements = permission_classes((IsAuthenticated,))(all_announcements)
    all_announcements = authentication_classes((TokenAuthentication,))(all_announcements)
all_announcements = api_view(['GET'])(all_announcements)

答案 2 :(得分:3)

这样做:

def my_decorator(condition):
    def wrap(fn):
        def new_f(*args,**kwargs):
            # some code that uses the function fn (fn holds a reference to the function you have decorated)
            pass

        if condition:
            return new_f
        else:
            return fn

    return wrap

@my_decorator(settings.USE_API_KEY)
def all_announcements(request):
    ...

(显然是一个一般的例子,你需要申请你的特定代码,其中很多你没有包含在你的问题中,所以我不能提供一个完整的例子供你复制粘贴!)

您可以将此视为my_decorator(condition)函数,返回一个新的装饰器wrap,然后装饰您的函数。装饰器wrap将使用条件来决定是否用new_f替换你的函数。

答案 3 :(得分:1)

这样的事情:

def my_conditional_wrapper(f):

    if not condition():
        return f

    def wrapper(*args, **kwargs):
        #wrap function here
        pass

    return wrapper

答案 4 :(得分:0)

如何?

def timeit(method):
    def timed(*args, **kw):
        if 'usetimer' not in kw:
            return method(*args, **kw)
        elif ('usetimer' in kw and kw.get('usetimer') is None):
            return method(*args, **kw)
        else:
            import time
            ts = time.time()
            result = method(*args, **kw)
            te = time.time()
            if 'log_time' in kw:
                name = kw.get('log_name', method.__name__.upper())
                kw['log_time'][name] = int((te - ts) * 1000)
            else:
                print '%r took %2.2f ms' % \
                      (method.__name__, (te - ts) * 1000)
            return result
    return timed

def some_func(arg1, **kwargs):
    #do something here

some_func(param1, **{'usetimer': args.usetimer})