Python/Django:是否有任何装饰器可以告诉输入不是空值?

4
  • 我是一名Java/Spring背景的新手,刚开始学习Django。
  • 请问在Django或Python中是否有类似以下代码的装饰器?

期望:

def addToList(@not_none a, @not_none b):
    # so that I do not check for nullity explicitly  
    do_things_with_a(a)
    do_things_with_b(b)
  • 由于在Java中很容易实现,所以只需要查看Python/Django是否有它

输入“null”是什么意思? - Ignacio Vazquez-Abrams
那不是装饰器语法。装饰器在函数或类级别上,而不是参数级别上。无论如何,这不是Python中通常的做法。 - Chris Morgan
除非你明确地导致或允许它,否则它永远不会是 None - Ignacio Vazquez-Abrams
我应该说,下面的答案是为了在函数中拒绝空参数而设计的。它不会自动创建Django错误页面或停止处理请求/表单。如果您想要验证表单输入,您需要阅读有关Django文档中表单验证的更多信息(特别是表单的clean()方法)。 - Simeon Visser
4个回答

5

Python通常不会限制数据类型。此外,修饰符只能应用于类和方法/函数。

尽管如此,你真的不应该这样做,但是如果一定要这样做,可以按照以下方式进行。(稍加修改即可接受参数名称以强制执行约束)。

def not_none(f):
    def func(*args, **kwargs):
        if any(arg is None for arg in args):
            raise ValueError('function {}: does not take arguments of None'.format(f.__name__))
        return f(*args, **kwargs)
    return func

@not_none
def test(a, b):
    print a, b

2
你可以编写一个装饰器rejectNone,如下所示:

def rejectNone(f):
    def myF(*args, **kwargs):
        if None in args or None in kwargs.values():
            raise Exception('One of the arguments passed to {0} is None.'.format(f.__name__)
        return f(*args, **kwargs)
    return myF

@rejectNone
def f(a, b, k=3):
   print a * b

如果您尝试使用None参数调用f,则现在会出现异常。请注意,装饰器可以应用于函数或类方法,但不能放在函数参数前面。


你没有从 myF 返回 f(*args, **kwargs) - Jon Clements

1

在我的第一个答案被删除后,这里是更新版本:

我试图使用Bigbob556677的非常好的答案,但对我来说,它与**kwargs不起作用,所以我进行了编辑并将其放在了Gist中,这里是https://gist.github.com/devTechi/6e633ded72cc83637f34b1a3f4a96984(代码也在下面)

我没有测试过只使用*args,但使用(我发布了更多或更少的Gist链接)**kwargs效果很好。

def not_none(nullable_parameters=None):
  # values given by real_decorator (see below)
  def the_actual_test(f, expected_args_with_given, allowed_nullable_args):
    has_none = False
    bad_parameters = []

    for key, value in expected_args_with_given.items():
      if (value is None and nullable_parameters is None) or \
              (value is None and key not in nullable_parameters):
        bad_parameters.append(key)
        has_none = True

    if has_none:
      raise ValueError("[Function '{}' of '{}'] - IMPORTANT: Parameters '{}' cannot be None. ".format(f.__name__, f.__module__, bad_parameters))

  # here the code REALLY begins
  def not_null_decorator(original_func):
    import inspect
    has_self = False
    # f.__code__.co_varnames --> local variables (not only parameters), see: https://python-reference.readthedocs.io/en/latest/docs/code/varnames.html
    # get declared arguments from ogirinal function
    argspec = inspect.getargspec(original_func)
    if 'self' in argspec.args:
      argnames = argspec.args[1:]  # no self
      has_self = True
    else:
      argnames = argspec.args
    args_dict = dict.fromkeys(argnames)

    def get_args(*args, **kwargs):
      for arg in args:
        if arg in args_dict.keys():
          args_dict[arg] = arg
      for key, value in kwargs.items():
        if key in args_dict.keys():
          args_dict[key] = value

      return args_dict

    def wrapper_with_self(self, *args, **kwargs):
      the_actual_test(original_func, get_args(*args, **kwargs), nullable_parameters)
      return original_func(self, *args, **kwargs)

    def wrapper(*args, **kwargs):
      the_actual_test(original_func, get_args(*args, **kwargs), nullable_parameters)
      return original_func(*args, **kwargs)

    if has_self:
      return wrapper_with_self
    else:
      return wrapper

  return not_null_decorator

使用方法:

from .nullable_decorator import not_none

@not_none(nullable_parameters=["nullable_arg1", "nullable_arg2"])
def some_function(self, nullable_arg1=None, nullable_arg2=None, non_nullable_arg1=None):
   pass

@not_none()
def some_other_function(self, non_nullable_arg1=None, non_nullable_arg2=None):
   pass

1

我知道现在有点晚了,但对于那些可能会有帮助的人来说。

我有一个简单的存储库,基于Jon的答案,它接受可空字段这里的参数。


def not_none(nullable_parameters=None):

    def the_actual_test(f, args, filter_array):
        has_none = False
        bad_parameters = []

        if type(filter_array) is str:

            filter_array = [filter_array]

        if not filter_array:

            if any(arg[1] is None for arg in args):
                raise ValueError('function {}: Parameters cannot be None. '.format(f.__name__))

        elif type(filter_array) is list:
            for a in args:
                for ff in filter_array:
                    if a[0] != ff:
                        if a[1] is None:
                            has_none = True
                            bad_parameters.append(a[0])
                            break

        if has_none:
            raise ValueError('function {}: Parameters {} cannot be None. '.format(f.__name__, bad_parameters))

    def real_decorator(f):


        v_names = f.__code__.co_varnames

        def wrapper(*args, **kwargs):
            n_args = []

            for a in range(0, len(args)):
                n_args.append((v_names[a], args[a]))

            the_actual_test(f, n_args, nullable_parameters)
            result = f(*args, **kwargs)

            return result
        return wrapper

    return real_decorator

Usage

from not_none import not_none

@not_none()
def no_none(a,b):
    return (a,b)

@not_none(nullable_parameters=["b"])
def allow_b_as_none(a,b):
    return (a,b)

#passes
no_none(1,1)

#fails
no_none(None,1)

#passes
allow_b_as_none(1,None)

#fails
allow_b_as_none(None,1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接