4
  • 我是 Django 新手,来自 Java/Spring 背景。
  • 我想知道是否有类似以下的装饰器可以在 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 是否有它
4

4 回答 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
于 2012-07-16T12:58:54.813 回答
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

Exception如果您尝试f使用参数调用,您现在将得到一个None。请注意,装饰器可以应用于函数或类方法,但不能将它们放在函数参数的前面。

于 2012-07-16T12:57:02.443 回答
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

用法

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)
于 2018-12-05T19:34:17.067 回答
0

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

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

我没有用 just 测试它*args,但是(我或多或少只是发布了 gist-link)**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
于 2021-02-12T09:26:54.443 回答